简体   繁体   English

如果我安排一名工人每天在Heroku上运行,我怎么能确定它不会运行两次或被跳过?

[英]If I schedule a worker to run every day on Heroku, how can I be sure it doesn't run twice or get skipped?

I'm a bit confused as to how Clockwork, Sidekiq, and Redis all fit together on Heroku given that Heroku restarts dynos at least once a day. 鉴于Heroku每天至少重启一次dynos,我觉得Clockwork,Sidekiq和Redis如何在Heroku上完全融合,我有点困惑。

Say I have a worker that runs once a day, so it's configured in config/clock.rb as: 假设我有一个每天运行一次的工作者,所以它在config/clock.rbconfig/clock.rb为:

module Clockwork
  every(1.day, 'Resend confirmation') { ResendConfirmationWorker.perform_async }
end

In this worker, I get all the users who have created an account but haven't confirmed it within two days, and resend a confirmation email to each of them. 在此工作人员中,我获得了创建帐户但尚未在两天内确认帐户的所有用户,并向每个帐户重新发送确认电子邮件。

class ResendConfirmationWorker
  include Sidekiq::Worker
  sidekiq_options queue: :resend_confirmation, retry: false

  def perform
    d = Time.zone.now - 2.days
    users = User.where.not(confirmation_sent_at: nil)
                .where(confirmed_at: nil)
                .where(created_at: d.beginning_of_day..d.end_of_day)

    users.find_each do |user|
      user.send_confirmation_instructions
    end
  end
end

Let's say someone signs up on Monday, this job runs on Wednesday, finds them, and sends them a second confirmation email. 假设有人在星期一报到,这个工作在周三运行,找到他们,并向他们发送第二封确认电子邮件。 Then the dyno gets restarted for whatever reason, and the job runs again. 然后dyno因任何原因重新启动,并且作业再次运行。 They'll get yet another email. 他们会收到另一封电子邮件。 Or alternatively, if the restart happens the moment before the job needs to run, then they won't get anything. 或者,如果重新启动发生在作业需要运行之前的那一刻,那么它们将无法获得任何结果。

How does Clockwork have any concept of jobs longer than 24 hours, given that its “lifespan” in a Heroku dyno? 鉴于其在Heroku dyno中的“寿命”,发条如何有超过24小时的任何工作概念? Is there a way to simply manage this limitation without having to constantly save this sort of thing to the database? 有没有办法简单地管理这个限制,而不必经常将这种东西保存到数据库?

If you know that you will execute it every wednesday, I suggest to use Heroku Scheduler ( https://devcenter.heroku.com/articles/scheduler ). 如果你知道你将在每个星期三执行它,我建议使用Heroku Scheduler( https://devcenter.heroku.com/articles/scheduler )。 It lets you run specific commands at set time intervals. 它允许您以设定的时间间隔运行特定命令。 Less complexity. 减少复杂性。

IMO you need more information in the database if you want to avoid such issues. IMO如果要避免此类问题,则需要在数据库中获取更多信息。 A state machine might help or an explicit second_confirmation_send_at column. 状态机可能有帮助或显式second_confirmation_send_at列。

That would allow you to write the query in your job like this: 这将允许您在工作中编写查询,如下所示:

users = User.where('confirmation_sent_at < ?', 2.days.ago)
            .where(second_confirmation_send_at: nil)

Then the query doesn't care anymore if it runs multiple times a day, or by accident a day later. 如果它一天运行多次,或者一天后意外运行,则查询不再关心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM