mca*_*mir 6 activerecord ruby-on-rails callback thread-safety ruby-on-rails-3
这段代码线程安全吗?
MyModel.skip_callback(:save, :before, :my_callback)
my_model_instance.update_attributes(attributes)
MyModel.set_callback(:save, :before, :my_callback)
Run Code Online (Sandbox Code Playgroud)
我可以安全地使用它来避免递归地重新触发相同的回调吗?
这是一个例子
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
Run Code Online (Sandbox Code Playgroud)
skip_callback并且set_callback不是线程安全的.我尝试在sidekiq(一个线程异步作业处理器)中创建一些记录时能够确认这一点.一旦我重新启用回调,就会出现一个竞争条件,导致调用回调.如果我评论回调重新激活代码,则没有问题.
我找到了一些可能的解决方案,包括两个宝石:
偷偷摸摸的拯救宝石似乎是这里最直接和最有意思的选择.gem基本上绕过ActiveRecord持久化方法并执行直接的sql.
它也是我唯一可以自信地说是线程安全的.它也是一个非常小且可以理解的宝石.缺点是它不会调用验证.因此,您需要自己调用验证.
Anand A. Bait在数字选项上汇总了一个很好的概述.我怀疑所有五个选项都是线程安全的.上面提到的两个宝石与Anand的帖子中的其他可能选项一起列出:http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/