Rails 3 ActiveRecord .skip_callback线程安全

这段代码线程安全吗?

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

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

这是一个例子

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

我找到了一些可能的解决方案,包括两个gem:

  • ‘偷偷摸摸’的gem
  • ‘skip_activerecord_callbacks’gem

偷偷摸摸的拯救gem似乎是这里最直接和最有意思的选择。 gem基本上绕过ActiveRecord持久化方法并执行直接sql。

它也是我唯一可以自信地说是线程安全的。 它也是一个非常小且可以理解的gem。 缺点是它不会调用validation。 因此,您需要自己调用validation。

Anand A. Bait在数字选项上加入了一个很好的概述。 我怀疑所有五个选项都是线程安全的。 上面提到的两个gem与Anand的post中的其他可能选项一起列出: http : //www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/