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

How to skip a callback after triggered[rails]

我有这样的回调: 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

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

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

您添加的回调只会在您每次 :create:update 模型时触发,也就是说,如果您创建并更新它,则会触发两次。如果您在每次调用时都让一个工作人员排队,那么您将在传递给 perform_atrun_time 处执行该工作。

根据您在这里的最终目标,您可以做很多事情。你想通知一次,永远,不管后续更新吗?或者您只是不想让用户收到大量通知?

在第一种情况下,我会将逻辑移至工作人员:

  • 保持这样的回调(好吧,重构它以简化代码)
  • 在您将作业加入队列时,即在回调的最后一步,将 notified 布尔标志添加到您设置为 true 的模型。
  • 在worker中,检索对象,如果之前是notified,则跳过,什么都不做。
  • 然后你可以把perform_at改成普通的perform_async

在第二种情况下,您可能希望使用 "notify first thing and then wait for 1 hour no notify anything else" 之类的东西。

  • 更改日期时间 notified_at 属性的布尔值并将其存储到回调中的 Time.current
  • 定义一个时间 window 来对通知进行分组,例如在模型 NOTIFICATION_WINDOW = 1 中以常数表示,例如以小时为单位。
  • 在 worker 中,更改您的逻辑以检查 your_object#notified_atYourObject#NOTIFICATION_WINDOW.hours.ago 以查看是否需要通知或丢弃。
  • 也将您的 perform_at 更改为 perform_async,所以现在通知并保持沉默一个小时。
  • 请记住,此方法将通知第一件事 (:create),并且在一个小时内不会对接下来的任意数量的 :update 做任何事情。

如果您想要更智能的东西,例如 "grouping a bunch of notifications" 并将它们一起发送,那么您需要一种不同的方法。例如,在你的数据库中写入 Notification 条目,其中有一些 notified 布尔标志,然后安排一个 rake 任务从DB 并按您喜欢的方式分组派遣它们。这将意味着从您当前的回调中删除工作人员并创建一个不同的工作人员,该工作人员将定期安排(每 5 分钟?每小时?)。

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