2011-01-13 1 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

아니요. 두 트랜잭션이 모두 동일한 리소스 (이 경우 @account)를 요청하고 (따라서 잠그고 있기 때문에) 교착 상태에 빠졌습니다. 이런 식으로 쓰레드를 사용해야한다면 Mutex 클래스를 사용하여 교착 상태가 발생하지 않도록하는 것이 좋습니다. (Google 뮤텍스 및 스레드 및 많은 예제를 찾을 수 있습니다.) – 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 

: 당신은 동시성이 일어나는 지점의 보장이 없습니다. 루비 길도 도움이되지 않습니다. 쓰레드 대신 포크를 사용하거나 fork_break gem을 사용해야합니다 : https://github.com/remen/fork_break