如何在触发后跳过回调[rails]

时间:2018-08-10 08:04:00

标签: ruby-on-rails-4 callback

我有这样的回调: after_commit :sponsored_notification, on: [:create, :update]

def sponsored_notification
      current_time = Time.now.in_time_zone(self.try(:timezone)).strftime("%Y-%m-%d %H:%M:%S")
      if current_time < self.try(:notify_time) && self.try(:is_sent) == false
        run_time = self.updated_at + (self.try(:notify_time) - current_time.to_time).seconds
        SponsoredNotificationWorker.perform_at(run_time, self.id)
      end
    end

我的问题是,当我创建一个赞助者然后更新它时,我收到了两个通知,但是我只想收到一个,应该发送最新的赞助者信息。我以为在这种情况下,回调被触发了两次。如果发生更新,如何跳过创建操作?

1 个答案:

答案 0 :(得分:1)

我认为您需要重新考虑流程的外观,然后重构代码以添加片段以实现您所描述的内容。

您添加的回调仅在您:create:update模型时才会触发,也就是说,如果您创建并更新该模型,则两次。如果您在每个呼叫中​​让一个工作人员排队,那么您将在传递给run_time的{​​{1}}处执行该工作。

根据这里的最终目标,您可以做很多事情。您是否想一次通知一次,而不考虑后续更新?或者,您只是不想向用户发送通知?

在第一种情况下,我将逻辑移至工作程序:

  • 像这样保持回调(嗯,重构它以简化代码)
  • 在入队的那一刻,即在回调的最后一步,向您设置为perform_at的模型添加notified布尔标志。
  • 在工作程序中,检索对象,如果该对象以前是true,则跳过该对象,不要执行任何操作。
  • 然后,您可以使用简单的notified来更改perform_at

在第二种情况下,您可能希望使用“通知第一件事,然后等待1个小时,不通知其他任何东西”之类的内容。

  • 将该布尔值更改为日期时间perform_async属性,并将其存储到回调中的notified_at中。
  • 定义一个时间窗口,以将通知分组(例如在模型Time.current中的常量,例如以小时为单位)。
  • 在工作进程中,更改逻辑以针对NOTIFICATION_WINDOW = 1检查your_object#notified_at,以查看是否需要通知或丢弃。
  • 也将您的YourObject#NOTIFICATION_WINDOW.hours.ago更改为perform_at,所以请立即通知并保持一个小时的沉默。
  • 请记住,这种方法将通知第一件事(perform_async),并且在接下来的一个小时内:create之后的任何时间都不会做任何事情。

如果您想要更智能的东西,例如“将一堆通知分组”并将它们一起发送,那么您需要一种不同的方法。例如,在您的数据库中写入:update个布尔标志的Notification项,然后安排一个notified任务以从数据库中获取所有rake unnotified您可以根据需要将DB分组并分批分发。这将意味着从当前的回调中删除该工作线程,并创建一个将定期调度的工作线程(每个5分钟?每小时?)。

这些是一些可能符合您要求的想法。首先澄清一下,尝试一些尝试,也许我们可以进一步缩小范围。