这段代码线程安全吗?
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
skip_callback
and set_callback
不是线程安全的。我在尝试在 sidekiq(线程异步作业处理器)中创建一些记录时能够确认这一点。一旦我重新启用回调,就会出现竞争条件,导致回调被调用。如果我评论回调重新激活代码,就没有问题。
我找到了许多可能的解决方案,其中包括两个要点:
- “偷偷保存”的宝石
- 'skip_activerecord_callbacks' 宝石
偷偷摸摸的保存宝石似乎是这里最直接、最能暴露意图的选择。 gem 本质上绕过了 ActiveRecord 持久性方法并直接执行 sql。
这也是我唯一可以自信地说是线程安全的。它也是一个非常小且易于理解的宝石。缺点是它不调用验证。因此,您需要自己调用验证。
阿南德·A·贝特 (Anand A. Bait) 总结了一些选项。我怀疑所有五个选项都是线程安全的。上面提到的两种宝石与其他宝石一起列出possibleAnand 帖子中的选项:http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/ http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)