0

我正在使用 Sidekiq 在后台执行一些繁重的处理。我在网上查了一下,但找不到以下问题的答案。我在用:

Class.delay.use_method(listing_id) 

然后,在课堂上,我有一个

self.use_method(listing_id)
    listing = Listing.find_by_id listing_id
    UserMailer.send_mail(listing)
    Class.call_example_function()

两个问题:

  1. 如何使这个函数对 UserMailer sendmail 是幂等的?换句话说,如果延迟方法运行两次,我如何确保它只发送一次邮件?将它包装在这样的工作中吗?

    mail_sent = false if !mail_sent UserMailer.send_mail(listing) mail_sent = true end

我猜不是因为再次尝试该功能,然后 mail_sent 设置为 false 以进行第二次运行。那么如何使 UserMailer 只运行一次。

  1. 在延迟异步方法中调用的函数也是异步的吗?换句话说, Class.call_example_function() 是否异步执行(不是响应/请求周期的一部分?)如果不是,我应该使用 Class.delay.call_example_function()

总的来说,只是熟悉 Sidekiq,所以任何想法都会受到赞赏。

谢谢

4

2 回答 2

6

我来晚了,但是一直在循环并且这个 StackOverflow 条目通过谷歌显着出现,它需要澄清。

幂等性问题和唯一工作问题不是一回事。“独特”的宝石会在作业即将被处理时查看作业的参数。如果他们发现在某个到期时间窗口内提交了具有相同参数的另一个作业,则该作业实际上并没有被处理。

宝石实际上就是他们所说的那样。他们考虑在特定时间窗口内排队的工作是否是唯一的。它们不会干扰重试机制。对于 OP 的问题,如果抛出错误从而导致作业重试,电子邮件仍会发送两次Class.call_example_function(),但前一行代码已成功发送电子邮件。

旁白:在撰写本文时,另一个答案中提到的sidekiq-unique-jobsgem 尚未针对 Sidekiq 3 进行更新另一种方法是sidekiq-middleware做同样的事情,但已经更新。

OP 的电子邮件问题有许多可能的解决方案,而正确的解决方案只有 OP 才能在其应用程序和执行环境的上下文中进行评估。一种是:如果电子邮件只发送一次(“恭喜,你已经注册了!”),那么包装在事务中的用户模型上的一个简单标志应该可以解决问题。假设一个类可以通过viaUser作为关联访问,并在模型中添加一个布尔标志(使用迁移),然后:Listinglisting.usermail_sentUser

listing = Listing.find_by_id(listing_id)

unless listing.user.mail_sent?
  User.transaction do
    listing.user.mail_sent = true
    listing.user.save!
    UserMailer.send_mail(listing)
  end
end

Class.call_example_function()

...因此,如果用户邮件程序引发异常,事务将回滚并且对用户标志设置的更改被撤消。如果“call_example_function”代码抛出异常,则作业失败并稍后重试,但用户的“已发送电子邮件”标志在第一次尝试时成功保存,因此不会重新发送电子邮件。

于 2014-04-10T02:17:41.473 回答
1

关于幂等性,您可以使用https://github.com/mhenrixon/sidekiq-unique-jobs gem:

所需要的只是您专门将 sidekiq 选项设置为 unique 为 true,如下所示:

sidekiq_options unique: true

对于将来安排的作业,可以设置作业应该是唯一的多长时间。该作业在配置的秒数内或在作业完成之前将是唯一的。

*如果您希望独特的工作即使在成功处理后仍然存在,那么只需将 unique_unlock_order 设置为除 :before_yield 或 :after_yield 之外的任何内容(unique_unlock_order = :never)

我不确定我是否理解问题的第二部分 - 当您delay调用方法时,整个方法调用都会推迟到 sidekiq 进程。如果通过“响应/请求周期”表示您正在运行 Web 服务器,并且您delay从那里调用,那么其中的所有调用use_method都是从 sidekiq 进程调用的,因此在该周期之外。尽管它们相对于彼此被同步调用......

于 2014-02-12T11:48:50.357 回答