2011-01-13 12 views
1

RSpecを使用して並列トランザクションをテストする方法はありますか? 私は、銀行口座の残高を、トランザクション内でロックしてから、それを減らしたり増やしたりする必要があると言います。 しかし、現在RSpec transactional_fixturesオプションを無効にしていますが、2つの分離したスレッドで2つの並列トランザクションを起動することはできません。なんらかの理由で、両方が吊るされています。アカウントを考える がモデル ですその後、この仕様がハングします:RSpecを使用した並列トランザクションのテスト

it "should ensure operations are performed correctly" do 
    @account = Account.create(:balance => 0) 
    threads = [] 
    (0..1).each do |index| 
    threads << Thread.new do 
     Account.transaction do 
     account = Account.find(@account.id, :lock => true) 
     account.balance += 100 
     sleep 0.5 
     account.save! 
     end 
    end 
    end 
    threads.each{|t|t.join} 
    @account.reload.balance.should == 200 
end 

は、まだ取引の能力を発揮できるようにしながら、それがハングアップではないようにする方法はありますか?

答えて

0

なぜ同じ理由で、同じリソース上で並行して並行したトランザクションを実行したいのでしょうか。あなたの例では、正確に何を達成しようとしていますか?

あなたのコードでは、同じインスタンスを使用しているので、自分自身がデッドロックに陥っているという事実が予想されます。おそらくここで何をしようとしているのか考え直したいと思うでしょう。

+0

ARキャッシュで私の 'Account.find()'の結果はありますか? –

+0

いいえ、2つのトランザクションが同じリソース(この場合は@account)を要求している(したがってロックしている)ため、デッドロックが発生しています。 このようにスレッドを使用する必要がある場合は、Mutexクラスを使用して、デッドロックが発生しないようにすることをお勧めします。 (Googleのmutexとスレッドと多くの例があります)。 – grokling

1

スレッド内のデータベースとは別の接続を使用する必要があります。まず、メインスレッドを切断し、各スレッドに再接続し、最終的にメインに再接続し、そのよう:

ActiveRecord::Base.connection.disconnect! 
(0..1).each do |index| 
    threads << Thread.new do 
    ActiveRecord::Base.establish_connection 
    # ... 
    end 
end 
ActiveRecord::Base.establish_connection 

他の問題は、そのようにテストにあります。あなたは、同時実行が発生した時点の保証はありません。ルビーのGILも助けにならないでしょう。スレッドの代わりにフォークを使用するか、fork_break gemを使用してください:https://github.com/remen/fork_break

関連する問題