关于幂等性和功能的基本Sidekiq问题

时间:2014-02-12 04:10:51

标签: ruby multithreading sidekiq idempotent

我正在使用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(上市)    mail_sent = true 端

  2. 我猜不会因为再次尝试该函数,然后在第二次运行时将mail_sent设置为false。那么我该怎么做才能让UserMailer只运行一次。

    1. 延迟异步方法中调用的函数是否也是异步的?换句话说,Class.call_example_function()是异步执行的(不是响应/请求周期的一部分吗?)如果不是,我应该使用Class.delay.call_example_function()
    2. 总的来说,只是熟悉Sidekiq所以任何想法都会受到赞赏。

      由于

2 个答案:

答案 0 :(得分:4)

我进入这个晚了,但是已经绕过这个循环,并且这个StackOverflow条目通过Google突出显示,它需要澄清。

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

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

旁白:在撰写本文时,Sidekiq 3尚未更新另一个答案中提到的sidekiq-unique-jobs宝石。另一种选择是sidekiq-middleware,它做了很多相同的事情,但已经更新。

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

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”代码抛出异常,则作业失败并稍后将重试,但是第一次尝试成功保存了用户的“发送电子邮件”标志,因此不会重新发送电子邮件。

答案 1 :(得分:0)

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

  

只需要专门设置sidekiq选项即可   对于如下所示的唯一真实:   

sidekiq_options unique: true
     

对于将来安排的工作,可以设置多长时间   工作应该是独一无二的。这个职位的数量是独一无二的   配置秒数或直到作业完成。

     

*如果您希望独特的作业即使在成功处理后仍然存在,那么只需将unique_unlock_order设置为   除了之前的任何东西:before_yield或:after_yield(unique_unlock_order =   :从不)

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