I'm creating flight booking website in Rails. Booking information is stored in database in the following table:
USERNAME | FLIGHT FROM | FLIGHT TO | DATE OF FLIGHT | TIME OF FLIGHT | some additional information not relevant to this task ... |
I'm looking to send an email an hour (or some specific time) before the TIME OF FLIGHT on a DATE OF FLIGHT. What is the best approach to do it ? I was looking into Cron and delayed_job however both seem to be based more on intervals rather than executing a job at specific date and time.
Please help.
Thank you
The simplest approach is just to have a cron job set to run every 10 minutes and determine via a database query which flights now require a reminder e-mail. You can have an additional field in the database such as "REMINDER_SENT" so that you only send an e-mail once.
If you are already using delayed job then the cron job should just call a ruby script which adds a SendReminders job on to the queue. You can then manage all of the db querying, e-mail sending and db updating from a normal delayed job.
This approach saves you having to queue up a large number of future dated events and you don't need to worry about flight times changing or events getting lost. If you miss one event then the next run in 10 minutes will pick up all the flights anyway.
Are you required to send those notifications exactly one hour (or another time) in advance?
If not I would create a cron job that calls a rake task, say every 10 minutes. This task checks if there are notifications due and sends them. If you expect them to arrive 60 minutes before, with these settings you have a delivery timeframe between 60-70 minutes in advance, given the delays imposed by spam filters etc I think this is reasonable.
If you call the script more often (every minute), the precision is higher, but you might have trouble with concurrently running tasks.
Related
I'm migrating from Delayed_jobs to Resque and I have difficulties finding the best way to handle those cases:
A user can NOT add twice the same command to the list of jobs (e.g. "export all my data"). Only one export command at a time. For other it's fine to have many (e.g. send emails)
Some jobs should not run for more than 5 minutes, while other are allowed to run for 30 minutes. In both cases, I'd like to have a time-out in case process is blocked or is not completed on time.
Can add jobs to start in a few days
Inform the user on all their current & future jobs.
Can cancel some jobs (current and future) for the user
Keep ability to have different lists (mostly for priorities / slow and fast tasks)
I looked at resque-status and it seems like it provides the low level query, but I would still need to do my per user job management.
Suggestions on best way to handle this?
I'm playing with Rails 4.2 app which uses ActiveJob backed by resque/sidekiq for email scheduling. When a user creates newsletter campaign a new job is created and scheduled on certain date. That's all great but what happens when the user changes the delivery date.
In this case every job could check if it should be delivered or not thus invalid jobs would be ignored and only the last one would be executed. This could work but if a user would make 1k edits that would push 1k-1 invalid jobs into queue - not good. I believe that the existing job should be updated or replaced with a new one. As far as I know searching through the Redis queue for the job_id is slow.
What would be the proper way for rescheduling ActiveJobs in Rails (with resque/sidekiq)?
There is none, jobs are not meant to be rescheduled. You have answered your own question:
In this case every job could check if it should be delivered or not thus invalid jobs would be ignored and only the last one would be executed.
The alternative is to re-architect how you send campaigns: store the delivery date in the database and have cron check every minute for campaigns which need delivery now and create the Sidekiq job right then.
I need to implement user faced scheduler, like users have reports and might choose schedule when they want those reports being sent to them.
Requirements are quote complex, like there should be schedules like each 12 hours, each 30 minutes, each second day, at Fridays at 1am, last Sunday of the months etc.
Is there Rails solution for that our should I create it from the ground?
Thanks!
Most schedulers for rails and ruby depend on a static file. You can use a queuing system like Delayed Job and make every job enqueue itself for next time after success. Or you can do a basic SheduledJob model which relates to the user, and stores the periodicity, next execution and last execution. And use a normal (frequent) scheduled task engine like clockwork to check for pending jobs.
I'd like to make an email notification if SomeModel has not been updated for 2 hours.
What is the best way to implement it?
After a model has been saved, queue up a background job to run 2 hours from that time to send the email. When a new job is enqueued, remove any still-unrun jobs that are still on the queue.
resque-scheduler providers a pretty simple way of doing this, assuming you have redis up and running.
Personally I find the solution that #x1a4 proposes to be somewhat overkill. Given the relatively large window of 2 hours, I would just run a job periodically (say, once every 10-15 minutes), then search all Models for updated_at <= 2.hours.ago and send out the emails.
As for scheduling that job to run every 15 minutes, there are several options. You may use resque-scheduler, if you are using Resque. You may also use the standard system cron, but will incur some fairly substantial overhead starting Rails each time the job runs. I also have written a distributed scheduler gem (i.e. cron that can run on multiple machines, but act like it's only running on one), which uses Redis under the hood.
My question is how could run x quantities of jobs each n seconds with delayed job gem?
Example
I want send massive newsletter. However when I send #50 ("example") mail, GMail doesn´t send the emails (SPAM) however its contents is a bit different.
So if I send the newsletter by groups of twenty user each 3 minutes perhaps GMail will send the emails correctly.
Thanks in advance
delayed_job has an option :run_at(https://github.com/collectiveidea/delayed_job), you can use that to set at what time the job should run. It doesn't guarantee if job would run at that time, but it would surely not run before that.
So, 20 mails/3 minutes = 1 email/9 seconds.
You can do somethings like this:
now = Time.now
count = 0
# then for each newsletter schedule it at intervals of 9 secs
users.each do |u|
WhateverMailer.delay(:run_at => now + count*9).news_letter(u)
count += 1
end
You can do this type of thing with SimpleWorker, a cloud-based scheduling and background processing service. It offers DelayedJob-like capabilities but without having to manage servers and queues. (I work at Iron.io, makers of SimpleWorker).
You can schedule a job to run every X seconds or schedule multiple jobs to come onto queue at specific times (different priorities have different target run windows). Rather than pre-schedule a lot of jobs though, you'll probably want to have one or more master jobs that run on regular schedules and then queue up one or more slave jobs to send the actual emails (each checking the database to pick up the next set to send).
You can do use the same approach when facing thresholds with fetching data via APIs. Happy to discuss further if you'd like.
Ken