ruby-on-rails - Rails 3 ActiveRecord .skip_callback 线程安全

标签 ruby-on-rails ruby-on-rails-3 activerecord callback thread-safety

这段代码线程安全吗?

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

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

  • “偷偷摸摸”的 gem
  • 'skip_activerecord_callbacks' gem

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

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

    Anand A. Bait 总结了许多选项。我怀疑所有五个选项都是线程安全的。上面提到的两个 gem 与 Anand 在这里的帖子中的其他可能选项一起列出:http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/

    关于ruby-on-rails - Rails 3 ActiveRecord .skip_callback 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6723816/

    相关文章:

    ruby-on-rails-3 - Rails 3 功能测试 : Can't mass-assign protected attributes: controller, 操作

    ruby-on-rails-3 - Rails 3 更新连接表的属性(有很多,通过关联)

    ruby-on-rails - 无法使用 Rails 中的 Fog 将照片上传到 S3 : !! #<Excon::Errors::SocketError: 错误地址>

    ruby-on-rails - Rails has_many 通过避免重复

    ruby-on-rails - RSpec:测试 Controller 时对模型的期望不起作用

    ruby-on-rails - 使用 rubocop 在 Emacs Flycheck 模式下出错

    mysql - 哪里用MongoDB,哪里用MySQL?

    ruby-on-rails - Rails 每当 gem 在通过 capistrano 部署时出错

    ruby-on-rails - 加载错误 : cannot load such file -- roo

    PHP 数据访问设计模式以补充 ORM