悲観的ロックのテストを書くことがあって調べたら、それっぽい記事を発見したが、ペーペーは読んで??だったから、自分用に噛み砕いたものをメモ。
記事の例として挙げられている、銀行口座のように、同一のデータに対して、複数のユーザーから更新処理が実行される場合に、どちらかの処理をブロックしてデータの競合を避ける必要がある。
- 複数のユーザーがログインしている状態を実現するために、usersをmapしてuser毎に作成したThreadの配列を生成。
- Threadの配列をeachして、Thread#joinで処理が終了するのを待ち、終わったらThreadをdeadにするようにする。
- Mutex#syncronizeでマルチスレッド時の処理を同期実行するようにしたけど、これだとテストできてないのか? ><
- ロックが効いてて、データが更新されていないことを確認する。
describe 'Transaction Lock' do
# ロールバックせずに保存するようにする
self.use_transactional_fixtures = false
mutex = Mutex.new
describe '悲観ロックのテスト' do
it 'お金消えたり増えたりしてないよね' do
users.map { |user|
Thread.new {
# マルチスレッドで複数の処理が競合しないようにMutex#syncronizeで処理をブロックする。
# mutex使っちゃったらマルチスレッドの意味無くなるのかな。。。分かる方教えてください m__m
mutex.synchronize do
# スレッド毎にDB接続
ActiveRecord::Base.connection_pool.with_connection do
# 悲観的ロック
end
end
}
}.each(&:join)
# お金消えたり増えたりしてないことを確認
expect(...).to eq(...)
end
end
end
参考
RubyのThread
Thread#join
Rubyで基礎的なマルチスレッドプログラミングをするためのサンプル
RubyのThread、Fiber、Kernel、forkで並列処理やプロセスの深淵へ
RubyのThreadを利用したWebサーバーを作る
RubyでThreadを使う
irbから学ぶRubyの並列処理 ~ forkからWebSocketまで