如何在 Heroku 上处理 运行 长的作业?

How do I handle long running jobs on Heroku?

我想使用 Heroku,但事实上他们每 24 小时随机重启一次测功机,这让事情变得有点困难。

我有一系列非常重要的处理支付处理的工作,我希望它们得到数据库的支持,以便它们 100% 可靠。为此,我选择了速度较慢的DJ。

因为我选择了 DJ,这意味着我也不能一次将 5,000,000 个事件推送到数据库(每封电子邮件发送 1 个)。

正因为如此,我有更长的 运行 工作(在几个小时内发送 200,000 条短信)。

对于这些较长的 运行 作业,如果它们在中间被切断,则让它们继续工作会更具挑战性。

heroku 似乎发送了 SIGTERM,然后期望进程在 30 秒内关闭。这不会发生在我的长期工作中。

现在我不确定如何处理它们...我能想到的唯一方法是在发送文本(例如 sms_sent_at 列)后立即更新数据库,但是只是意味着我正在破坏数据库性能,而不是为每个批次发送一个更新查询。

如果我可以安排重新启动,这会好很多,至少我可以在晚上完成,那时我 99% 可能不会 运行 任何不需要更长时间的工作关机时间少于 30 秒。

或者.. 换句话说,我可以 'listen' for SIGTERM 在一个长的 运行 DJ 中并且至少提前中止循环以便稍后可以恢复吗?

手动重启将重置 24 小时时钟 - heroku ps:restart 在您喜欢的时间应该可以让您获得所需的控制权。

可以在此处找到更多信息:Dynos and the Dyno Manager

这是正确的答案,你听 SIGTERM(我在这里使用 DJ)然后优雅地救援。重要的是作业是幂等的。

Long running delayed_job jobs stay locked after a restart on Heroku

class WithdrawPaymentsJob

  def perform
    begin
      term_now = false
      old_term_handler = trap('TERM') { term_now = true; old_term_handler.call }

      loop do

        puts 'doing long running job'
        sleep 1

        if term_now
          raise 'Gracefully terminating job early...'
        end
      end

    ensure
      trap('TERM', old_term_handler)
    end
  end

end

这里是你如何用 Que 解决它:

    if Que.worker_count.zero?
      raise 'Gracefully terminating job early...'
    end