覆盖activerecord回调以异步运行它们

时间:2018-12-04 12:40:22

标签: ruby-on-rails activerecord jruby concurrent-ruby

我正在开发Rails应用,目前我们正在迁移到jruby。 我们目前在其中一个模型上有超过10个回调函数,这很长时间以来一直阻止响应。

after_update :sync
after_update :send
after_create :add
after_create :add
after_create :send
after_update :track!
after_create :track!
after_create :send_welcome_email
after_create :track
after_update :send
after_update :set_is_active!
after_update :set_
after_create :apply
after_update :apply
after_update :clear
after_create :mark

我需要包装/覆盖activerecord的after回调(after_save,after_update),以使用并发红宝石异步运行它们,以不阻止响应,但我不知道如何正确地做到这一点。

我想做的就是这样

require 'concurrent'
class ApplicationRecord < ActiveRecord::Base
  def after_update
    Concurrent::Promise.new { super }.exec
  end
end

我只需要知道正确的语法以及这种方法是否正确即可。 将不胜感激任何建议。

1 个答案:

答案 0 :(得分:0)

这里没有一般性建议-您需要对应用程序有所了解。

需要注意的几件事:

  • 听起来像您在回调地狱中,也许需要重新考虑一下体系结构-缩小模型范围和/或使用观察者(以简化)

  • 您当然可以将执行移到另一个线程中,但是在执行操作后最好不要依赖于彼此的状态

  • 如果后续执行DB操作的那些人也要意识到它们在“主”事务之外运行

  • 最后但并非最不重要的一点是不要忘记进行清理-应将AR连接放回池中,因为Rails不会为您这样做(与请求线程一样),除非您明确告知

通常可以这样处理:如果您需要等待完成,并且您的回调需要顺序运行,则将它们移至另一个线程不会有太大影响。如果不是这种情况,请尝试一下,然后考虑是否要让所有的Promise运行在同一(默认)执行程序上,还是想显式定义不同的Promise(例如,用于CPU密集型任务还是IO绑定任务)。