I want to run a task every minute on Heroku to check if conditions are met to time-out certain user tasks. I can only run a Heroku cron job every hour, so what's the best way to set up a timed task like this. I am using Rails 3.1 on Heroku.
scheduling a job every minute Rails 3.1 on Heroku
Asked Answered
You could use delayed_job with a self-restarting job with a :run_at
. Something sort of like this:
class YourJob
def do_interesting_things
#... Do what needs to be done.
self.delay(:run_at => 1.minute.from_now).do_interesting_things
end
def self.start_me_up
new.do_interesting_things
end
end
And then somewhere during your application's initialization:
YourJob.start_me_up
thank you - i will try that today and if it works i'll accept the answer :-) –
Ticon
Did this work out? I'm needing to run a rake task every 1 minute and I'm thinking that there should be a way to make it run itself vs requiring cron. Presently cron on heroku has a max of every hour. –
Bioenergetics
@ylluminate: I never heard back but it should work, try it and let me know how it goes. –
Honeycomb
You should probably wrap the whole "do what needs to be done" in a big
begin
,rescue
block or else your job won't restart if anything ever goes wrong. –
Highpitched @muistooshort i did this, but it looks like one of the workers is constantly running. i guess that is how sidekiq/delayedjob implements it? –
Misusage
@mingyeow: DJ usually has a
rake jobs:work
running in the background all the time, that's the process that looks for newly enqueued delayed jobs and runs them. –
Honeycomb won't this recursive function lead to a stack overflow? –
Stanwood
@mhz: The method isn't really recursive. The
delay
call adds an entry to the DelayedJob queue and DJ will call do_interesting_things
when it scans the queue. So do_interesting_things
isn't really calling itself, it is asking DJ to call itself later. –
Honeycomb @muistooshort it doesn't work? I get an error of "uninitialized constant YourJob" should the method be defined
def self.do_interesting_things
? –
Stanwood @mhz: What is your class called? Presumably something more sensible than
YourJob
. –
Honeycomb Its called
VrEmailJob
... though not sure why that would be a problem....? Its inheriting from ActiveJob::Base –
Stanwood @Stanwood Then why are you using
YourJob
? This answer is about delayed-job, you'll have to adapt it a little to use it with ActiveJob and you'll have to use the right class names. –
Honeycomb @muistooshort I only said
YourJob
in the comment to put it in the context of this question... I'm not actually using YourJob
in my code. I also spent too many hours trying to make delayed_jobs work, and now the jobs are disappearing mysteriously from my database. I'm going to throw in the towel here and try another solution, but thanks anyway. –
Stanwood As of today, you can the scheduling gem, clockwork. Heroku officially supports this and you can find their documentation here.
Just note that clockwork requires a dyno, so it will cost the same as any other type of dyno ($0.05 per hour, billable to the second -- about $35/month). Those who don't require scheduling "every minute", but are fine with every 10 minutes, every hour, or every day (at a specific time), then consider the Heroku Scheduler, a free add-on. –
Unharness
Another limitation of clockwork is that it can only run on a single dyno, so if you have more scheduled work than a single process can handle, the
delayed_job
solution will work better. –
Highpitched You could use delayed_job with a self-restarting job with a :run_at
. Something sort of like this:
class YourJob
def do_interesting_things
#... Do what needs to be done.
self.delay(:run_at => 1.minute.from_now).do_interesting_things
end
def self.start_me_up
new.do_interesting_things
end
end
And then somewhere during your application's initialization:
YourJob.start_me_up
thank you - i will try that today and if it works i'll accept the answer :-) –
Ticon
Did this work out? I'm needing to run a rake task every 1 minute and I'm thinking that there should be a way to make it run itself vs requiring cron. Presently cron on heroku has a max of every hour. –
Bioenergetics
@ylluminate: I never heard back but it should work, try it and let me know how it goes. –
Honeycomb
You should probably wrap the whole "do what needs to be done" in a big
begin
,rescue
block or else your job won't restart if anything ever goes wrong. –
Highpitched @muistooshort i did this, but it looks like one of the workers is constantly running. i guess that is how sidekiq/delayedjob implements it? –
Misusage
@mingyeow: DJ usually has a
rake jobs:work
running in the background all the time, that's the process that looks for newly enqueued delayed jobs and runs them. –
Honeycomb won't this recursive function lead to a stack overflow? –
Stanwood
@mhz: The method isn't really recursive. The
delay
call adds an entry to the DelayedJob queue and DJ will call do_interesting_things
when it scans the queue. So do_interesting_things
isn't really calling itself, it is asking DJ to call itself later. –
Honeycomb @muistooshort it doesn't work? I get an error of "uninitialized constant YourJob" should the method be defined
def self.do_interesting_things
? –
Stanwood @mhz: What is your class called? Presumably something more sensible than
YourJob
. –
Honeycomb Its called
VrEmailJob
... though not sure why that would be a problem....? Its inheriting from ActiveJob::Base –
Stanwood @Stanwood Then why are you using
YourJob
? This answer is about delayed-job, you'll have to adapt it a little to use it with ActiveJob and you'll have to use the right class names. –
Honeycomb @muistooshort I only said
YourJob
in the comment to put it in the context of this question... I'm not actually using YourJob
in my code. I also spent too many hours trying to make delayed_jobs work, and now the jobs are disappearing mysteriously from my database. I'm going to throw in the towel here and try another solution, but thanks anyway. –
Stanwood Clockwork is the way to go but I will suggest another workaround.
Use scheduler (every 10min) + delayed jobs to execute the task every minute. This seems a little bit more reliable solution than the one without scheduler.
MyJob.run!
(1..8).each |i|
MyJob.delay(run_at: i.minutes.from_now).run! # create 8 more jobs (each start 1 minute later)
end
© 2022 - 2024 — McMap. All rights reserved.