如何在Heroku上安排一个“每周”任务?

22

我在Heroku上部署了一个Rails应用,并成功使用Heroku Scheduler添加了每日作业。

现在我想要一个每周作业,但是调度程序附加组件不允许我选择每周选项。

您有什么建议可以实现这一点:

  • 我曾经尝试过使用rufus-scheduler,但它给我带来了一些问题,所以这不是一个选择。详见这里
  • 我正在考虑检查每日工作中的当前日期。是否有人尝试过并提供反馈或知道该方法的问题?
  • 非常感谢其他的想法。
5个回答

38

有一个方法可以用你提到的第二个小点:

启用Heroku cron插件,然后在app/lib/tasks中添加一个cron.rake任务

启用Heroku scheduler插件,然后在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建议转换到他们的计划程序添加。但是这并不改变每周作业的方法。

编辑2:根据sunkencity的反馈对我的答案进行调整。


3
计划任务插件已不建议使用,将被替换为调度器插件。话虽如此,您提出的方法是可行的,但可以使用activesupport更好地表述:Time.now.friday? - sunkencity
我对硬编码日期的想法感到不安,因此我现在将保持问题开放,以寻找更好的替代方案。 - T C
1
顺便说一下,我的做法是使用Heroku配置变量来运行每周的某一天。然后你需要通过UI控制时间。这真的太好。如果Heroku团队在这里并且看到了这个,请改进调度程序。它不必具有cron的所有灵活性。但至少要让它可以安排每周和每月的任务。 - David S
我想到的一个小改进是使用一些元编程来为每天创建任务,例如your_weekly_task_monday、your_weekly_task_tuesday等。然后,您可以根据要运行的日期将所需任务添加到Heroku调度程序中,以便您不必将此配置放在应用程序中。 - mrbrdo
1
如果你想在每月的第一天(或任何一天)发送报告,可以这样做: 如果 Time.now.day == 1 - nfriend21

10

一种仅使用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 

9

虽然不是最理想的,但我已经开始通过添加一个RUN_IF环境变量到通过heroku:scheduler运行的rake任务来实现对作业进行每周和每月的调度。

# 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

如果运行 rake 任务时没有设置 RUN_IF 变量,它将运行。否则,除非 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)

与上面的其他想法类似,但我更喜欢将调度细节从应用程序代码中移出。


1

此处所讨论,并使用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

0
如果您不想或无法使用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)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接