How to prevent edge cases or delay for a deadline of a scheduled task? - ruby-on-rails

Suppose I have an event scheduled in the future with start_date, end_date (inclusive), timezone, and status. The dates are wall-time since users are from all of the places with different timezones. There will be incoming transactions and I'd like to check the validity of these transactions against the status of the task.
If the status of the task is active then it's still valid. What I'm planning to do is to setup a cron job (or ActiveJob in Rails) to run every 15 minutes to check whether the task has already started or ended according to the user's timezone setting and update the status field.
The problem is that suppose the task's end_date is 15 December and the cron job begins at exactly 16 December 00:00 at which the task should be already expired and the cron job takes approximately 2 minutes to complete the whole database. Then the status will updated to inactive at 16 around December 00:02. If there is a transaction coming in at 16 December 00:01 and then the application checks the validity against its status which is still active but in fact it's already past the deadline.
Any ideas how to combat this problem?
By the way, although the application itself is not really serious and can afford some mismatches, I'm still worried about the data intregrity when querying since there will be some datapoints missing out of the valid date range.

Cron won't work since it creates the problem you describe, but with activejob you can tell it the exact date and time to run https://edgeguides.rubyonrails.org/active_job_basics.html#enqueue-the-job
By the way, if something depends on a date, why don't you actually check that date instead of the "status" column?

Related

User faced scheduler for rails

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.

Should I use Delayed Job for long running background tasks?

I have an application where I want to automatically deactivate a user 72 hours after they have been activated. I have set this up with Delayed Job, but am now wondering if that is the best option.
My question is, if I set a task for 72 hours in the future, will a worker be active for that entire 72 hours? (I'm concerned about this as Heroku charges by the hour)
I'm open to suggestion here as far as better ways of doing this goes. One idea I had was to set this up using an exp_date column and check against that at sign in there by eliminating the need for DJ completely.
My question is, if I set a task for 72 hours in the future, will a worker be active for that entire 72 hours? (I'm concerned about this as Heroku charges by the hour)
Yes, it will be up all time. Delayed job continuously pings the database to see if there any job in its queue.
And, regarding the best option i think i rather put one column knows as valid_upto and put the date till will be active. I only signins (or whatever) to only those user which has created_at dates less then or equal to valid_upto date. And, periodically may be once in month i will run one cron job to remove invalid users.
And, like #leesungchul suggested, you can use that, that looks cool.
You can use the workless gem which is an addon for delayed jobs so you don't leave your worker running constantly on heroku.
https://github.com/lostboy/workless

Ruby on Rails - Automated Email Sending - Flight Reminder

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.

Managing timezones for different users

I have a website where I have many users coming from different countries. Users can schedule a task based on their timezone. Now there is a cron running on the server after every min, the cron executes a script which checks if there are any scheduled task of any user and if so it does the needful.
Since my server is based in the US, the script executed by the cron considers the timezone of the US. What do I have to do in my script that will execute the user's task based on user's timezone instead of server's timezone?
Thanks in advance for any ideas
Lookup the user's timezone.
Compute the current time in the user's timezone.
For each job, look up the last time it was run and compute the next time it should run.
For any job whose next run time is now or in the past, run that job and update the record of the last time each job was run.
I did something similar on the iPhone a few months ago.
My solution was to capture the time as a string. So if the user selected 8am, I would just capture 08:00 and their time zone e.g. Europe/London.
Every 5 minutes or so on my server, I could then convert this 08:00 into the current UTC time based on the timezone. If this time was "present", I would carry about a check on the user's transport status and issue alerts.
To help me with the TimeZones, I used NodaTime. http://noda-time.blogspot.co.uk/

Email notification when 'updated_at' become 2 hours before current time

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.

Resources