问题
I have a Rails app deployed on Heroku with the Heroku scheduler add-on successfully working for daily jobs.
Now I want a weekly job, but the scheduler add-on does not allow me a weekly option.
Any suggestions on how I could accomplish this:
- I've tried using rufus-scheduler in the past but it caused me some problems, so that's not an option. See here for detail.
- I'm thinking of something along the lines of checking for current day within a daily job. Has anyone tried it and have feedback or know of issues with the approach?
- Other ideas much appreciated.
回答1:
One approach would be the one of your 2nd bullet point:
activate the Heroku cron add-on, and add a cron.rake
task in app/lib/tasks
Activate the Heroku scheduler add-on, and add a scheduler.rake
task in app/lib/tasks
task :your_weekly_task=> :environment do
if Time.now.friday? # previous answer: Date.today.wday == 5
#do something
end
end
You even have the luxury of defining the day you want your task to run ;o) (5 is for Friday)
EDIT: by the way, Cron is deprecated and Heroku recommends switching to their Scheduler add-on. This doesn't change the approach for a weekly job though.
EDIT2: adjustments to my answer based on feedback from sunkencity.
回答2:
An alternate option using only shell code. Setup the Heroku scheduler hourly, and do a comparison against the date command:
# setting the schedular to run hourly at *:30 is equivalent to the
# crondate: 30 8 * * 1
if [ "$(date +%H)" = 08 ] && [ "$(date +%d)" = 01 ]; then YOUR_COMMAND ; fi
I've used this code to mimic cron in my local time zone:
nz_hour="$(TZ=NZ date +%H)" ; nz_day="$(TZ=NZ date +%d)" ; if [ "$nz_hour" = 08 ] && [ "$nz_day" = 01 ]; then YOUR_COMMAND ; fi
回答3:
It's not ideal, but I've taken to adding a RUN_IF environment variable to rake tasks run through heroku:scheduler which lets me weekly and monthly schedules for jobs.
# lib/tasks/scheduler.rake
def run?
eval ENV.fetch('RUN_IF', 'true')
end
def scheduled
if run?
yield
else
puts "RUN_IF #{ENV['RUN_IF'].inspect} eval'd to false: aborting job."
end
end
# lib/tasks/job.rake
task :job do
scheduled do
# ...
end
end
If a rake task is run without a RUN_IF variable it will run. Otherwise, the job will be aborted unless the value of RUN_IF evals to a falsey value.
$ rake job # => runs always
$ rake job RUN_IF='Date.today.monday?' # => only runs on Mondays
$ rake job RUN_IF='Date.today.day == 1' # => only runs on the 1st of the month
$ rake job RUN_IF='false' # => never runs (not practical, just demonstration)
Similar to other ideas above, but I prefer moving the scheduling details out of the application code.
回答4:
As discussed over here, and using the above logic from Rob, here are the bash scripts broken down by a day of the week, once a month, and on a specific date.
Run a task every Monday:
if [ "$(date +%u)" = 1 ]; then MY_COMMAND; fi
Run a task every 1st day in a month:
if [ "$(date +%d)" = 01 ]; then MY_COMMAND; fi
You could also run a job every year on December 24th:
if [ "$(date +%m)" = 12 ] && [ "$(date +%d)" = 24 ]; then MY_COMMAND; fi
回答5:
If you don't want or cannot do this with Rake, another option is to do this with Ruby from bash:
#!/bin/bash
cmd="echo your schedule job here"
# Only run on even days
ruby -e 'if Time.now.utc.day.even?; puts "Not today!"; exit 1; end' && $cmd "$@"
This works even for non-ruby projects (as in my case: Clojure).
来源:https://stackoverflow.com/questions/9835095/how-can-i-schedule-a-weekly-job-on-heroku