6

このコードはスレッドセーフですか?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 < 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 
+0

なぜ、あなたはbefore_saveまたはbefore_createを使用できませんか? – apneadiving

+0

最終要件は何ですか? – Anatoly

+0

ここには要件はありません。私はこのコードを使用していません。おそらく私は決してしませんが、インターネット上でこのソリューションを見つけ、マルチスレッドで使用するのが安全かどうか自分に尋ねました。 – mcasimir

答えて

5

skip_callbackset_callbackあるスレッドセーフではありません。 sidekiq(スレッド化された非同期ジョブプロセッサ)内にいくつかのレコードを作成しようとしている間、これを確認することができました。コールバックを再び有効にするとすぐにコールバックが呼び出される競合状態が発生します。私がコールバック再アクティベーションコードにコメントすると、問題はありません。

私は2つの宝石を含む問題に対する可能な解決策の数を発見した

  • 「卑劣な保存」宝石
  • 「skip_activerecord_callbacks」宝石

卑劣な-保存宝石は、ここで最も直接的で意図的に明らかになっているオプションのようです。本質的に、この宝石はActiveRecord永続性メソッドをバイパスし、まっすぐなSQLを実行します。

スレッドセーフであると確信できるのはこれだけです。それはまた非常に小さく理解できる宝石です。欠点は、検証を呼び出さないことです。したがって、自分で検証を呼び出す必要があります。

Anand A. Baitは、数多くのオプションをまとめました。 5つのオプションすべてがスレッドセーフであると私は懐疑的です。上記の2つの宝石は、Anandのポストに他のの可能性のあるオプションと一緒にリストアップされています:http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/

関連する問題