【问题标题】:How can I schedule a 'weekly' job on Heroku?如何在 Heroku 上安排“每周”工作?
【发布时间】:2012-04-07 18:29:52
【问题描述】:

我在 Heroku 上部署了一个 Rails 应用程序,其中 Heroku 调度程序插件成功地用于日常工作。

现在我想要每周工作,但调度程序插件不允许我每周选择。

关于如何完成此任务的任何建议:

  • 我过去曾尝试使用 rufus-scheduler,但它给我带来了一些问题,所以这不是一个选择。有关详细信息,请参阅here
  • 我正在考虑在日常工作中检查当天的情况。有没有人尝试过并有反馈或知道该方法的问题?
  • 非常感谢其他想法。

【问题讨论】:

    标签: ruby-on-rails heroku scheduled-tasks


    【解决方案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)。

          【讨论】:

            猜你喜欢
            • 2013-05-27
            • 1970-01-01
            • 2013-03-15
            • 2017-11-17
            • 1970-01-01
            • 2023-03-05
            • 2018-09-30
            • 2013-07-03
            • 2017-10-31
            相关资源
            最近更新 更多