Rails 3 ActiveRecord .skip_callback 线程安全

发布于 2024-11-24 01:34:12 字数 958 浏览 1 评论 0原文

这段代码线程安全吗?

MyModel.skip_callback(:save, :before, :my_callback)
my_model_instance.update_attributes(attributes)
MyModel.set_callback(:save, :before, :my_callback)

我可以安全地使用它来避免递归地重新触发相同的回调吗?

这是一个例子

class Blog < ActiveRecord::Base

  after_save  :update_blog_theme, :if => :active_theme_id_changed?

  # ...

  private

  def update_blog_theme

    # Reuses a previously used BlogTheme or creates a new one
    blog_theme = BlogTheme.find_by_theme_id_and_blog_id(
                      self.active_theme_id, 
                      self.id)

    blog_theme ||= BlogTheme.create!( 
                     :theme_id => active_theme_id, 
                     :blog_id => self.id )

    Blog.skip_callback(:save, :after, :update_blog_theme)
    self.update_attributes!(:active_blog_theme_id => blog_theme.id) 
    Blog.set_callback(:save, :after, :update_blog_theme)

  end

end

Is this code thread safe?

MyModel.skip_callback(:save, :before, :my_callback)
my_model_instance.update_attributes(attributes)
MyModel.set_callback(:save, :before, :my_callback)

Can i safely use it to avoid retrigger the same callback recursively?

Here is an example

class Blog < ActiveRecord::Base

  after_save  :update_blog_theme, :if => :active_theme_id_changed?

  # ...

  private

  def update_blog_theme

    # Reuses a previously used BlogTheme or creates a new one
    blog_theme = BlogTheme.find_by_theme_id_and_blog_id(
                      self.active_theme_id, 
                      self.id)

    blog_theme ||= BlogTheme.create!( 
                     :theme_id => active_theme_id, 
                     :blog_id => self.id )

    Blog.skip_callback(:save, :after, :update_blog_theme)
    self.update_attributes!(:active_blog_theme_id => blog_theme.id) 
    Blog.set_callback(:save, :after, :update_blog_theme)

  end

end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最偏执的依靠 2024-12-01 01:34:12

skip_callbackset_callback 不是线程安全的。我在尝试在 sidekiq(线程异步作业处理器)中创建一些记录时能够确认这一点。一旦我重新启用回调,就会出现竞争条件,导致回调被调用。如果我评论回调重新激活代码,就没有问题。

我已经找到了该问题的许多可能的解决方案,包括两个宝石:

  • “偷偷保存”宝石
  • “skip_activerecord_callbacks”宝石

“偷偷保存”宝石似乎是这里最直接和最能揭示意图的选项。 gem 本质上绕过了 ActiveRecord 持久性方法并直接执行 sql。

这也是我唯一可以自信地说是线程安全的。它也是一个非常小且易于理解的宝石。缺点是它不调用验证。因此,您需要自己调用验证。

阿南德·A·贝特 (Anand A. Bait) 总结了一些选项。我怀疑所有五个选项都是线程安全的。上面提到的两个宝石与 Anand 的帖子中的其他可能选项一起列出:http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/

skip_callback and set_callback are NOT thread safe. I was able to confirm this while trying to create some records within sidekiq (a threaded async job processor). As soon as I re-enable the callbacks, there is a race condition that results in callbacks being called. If I comment the callback re-activation code, there are no issues.

I have found a number of possible solutions to the issue including two gems:

  • the 'sneaky-save' gem
  • the 'skip_activerecord_callbacks' gem

The sneaky-save gem seems to be the most straight-forward and intention-revealing option here. The gem essentially bypasses the ActiveRecord persistence methods and executes straight sql.

It is also the only one that I can confidently say is thread-safe. It is also a very small and understandable gem. The downside is that it does not call validations. Thus you would need to call validations yourself.

Anand A. Bait put together a great rundown on a number options. I am skeptical that all five options are threadsafe. The two gems mentioned above are listed along with other possible options in Anand's post here: http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文