如何在 Heroku 上安排“每周”工作?
Posted
技术标签:
【中文标题】如何在 Heroku 上安排“每周”工作?【英文标题】:How can I schedule a 'weekly' job on Heroku? 【发布时间】:2012-04-07 18:29:52 【问题描述】:我在 Heroku 上部署了一个 Rails 应用程序,其中 Heroku 调度程序插件成功地用于日常工作。
现在我想要每周工作,但调度程序插件不允许我每周选择。
关于如何完成此任务的任何建议:
我过去曾尝试使用 rufus-scheduler,但它给我带来了一些问题,所以这不是一个选择。有关详细信息,请参阅here。 我正在考虑在日常工作中检查当天的情况。有没有人尝试过并有反馈或知道该方法的问题? 非常感谢其他想法。【问题讨论】:
【参考方案1】:一种方法是您的第二个要点:
激活 Heroku cron 插件,并在 app/lib/tasks
中添加 cron.rake
任务
激活 Heroku 调度器插件,并在app/lib/tasks
中添加一个scheduler.rake
任务
task :your_weekly_task=> :environment do
if Time.now.friday? # previous answer: Date.today.wday == 5
#do something
end
end
您甚至可以定义您希望任务运行的日期;o) (5 代表星期五)
编辑:顺便说一下,Cron 已被弃用,Heroku 建议切换到他们的调度程序插件。不过,这不会改变每周工作的方法。
EDIT2:根据 sunkencity 的反馈调整我的答案。
【讨论】:
cron 插件已被弃用,将停止使用,取而代之的是调度程序。也就是说,您建议的方法是合理的,但可以通过 activesupport 更好地制定:Time.now.friday? 我对硬编码这一天的想法感到畏缩,所以我暂时将这个问题留待更好的选择。 顺便说一句,我所做的是在一周中的某一天使用 heroku 配置变量来运行。然后,您必须通过 UI 控制一天中的时间。这真的不很棒。 Heroku 团队,如果您在那里阅读此内容,请改进调度程序。它不必具有 cron 的所有灵活性。但是,至少可以安排每周和每月的工作。 我想出的一个小改进是使用一些元编程来完成每天的任务,例如your_weekly_task_monday, your_weekly_task_tuesday 等。然后你可以根据你希望它运行的日期在 heroku 调度程序中添加你想要的任务,所以你不要把这个配置放在应用程序中。 如果您想在每月的第一天(或每月的任何一天)发送报告,您可以这样做:if Time.now.day == 1【参考方案2】:仅使用 shell 代码的替代选项。每小时设置 Heroku 调度程序,并与 date 命令进行比较:
# 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
我已使用此代码在我的本地时区模拟 cron:
nz_hour="$(TZ=NZ date +%H)" ; nz_day="$(TZ=NZ date +%d)" ; if [ "$nz_hour" = 08 ] && [ "$nz_day" = 01 ]; then YOUR_COMMAND ; fi
【讨论】:
【参考方案3】:这并不理想,但我已经开始添加一个 RUN_IF 环境变量来通过 heroku:scheduler 运行任务,这让我可以每周和每月安排工作。
# 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
如果在没有 RUN_IF 变量的情况下运行 rake 任务,它将运行。否则,作业将被中止,除非 RUN_IF 的值评估为假值。
$ 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)
与上述其他想法类似,但我更喜欢将调度细节从应用程序代码中移出。
【讨论】:
【参考方案4】:正如 over here 所讨论的,并使用 Rob 的上述逻辑,这里是按一周中的一天、一个月一次和特定日期分解的 bash 脚本。
每周一运行一个任务:
if [ "$(date +%u)" = 1 ]; then MY_COMMAND; fi
每月第一天运行一次任务:
if [ "$(date +%d)" = 01 ]; then MY_COMMAND; fi
您也可以在每年的 12 月 24 日运行一项工作:
if [ "$(date +%m)" = 12 ] && [ "$(date +%d)" = 24 ]; then MY_COMMAND; fi
【讨论】:
【参考方案5】:如果您不想或不能使用 Rake 执行此操作,另一种选择是使用 bash 中的 Ruby 执行此操作:
#!/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 "$@"
这甚至适用于非 ruby 项目(在我的例子中:Clojure)。
【讨论】:
以上是关于如何在 Heroku 上安排“每周”工作?的主要内容,如果未能解决你的问题,请参考以下文章