Rails 3.2.3 を使用し、tinyTDS を使用して接続する MS SQL Sever のインスタンスの上にあるアプリケーションを実行しています。アプリケーションは、ユニコーンを使用して 4 つのプロセスを持つマルチスレッド化されています。問題は、各リクエストに一意のアカウント番号を割り当てるためにインクリメントする必要がある番号を格納するために、アプリケーションがデータベース内のフィールドを使用することです。アプリケーションをローカルで実行しても、マルチスレッドではないため問題はありません。
ユニコーンを使用してステージング環境で実行しているときに、複数の同時リクエストでアプリケーションをヒットすると、10 人に 1 人程度が重複したカード番号で戻ってきます。私は以下を試しました。
レガシーコード
row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
next_card_number = row.value
row.value = (next_card_number.to_i + 1).to_s
row.save!
return next_card_number
レガシー コード + トランザクション
CardValue.transaction do
row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
next_card_number = row.value
row.value = (next_card_number.to_i + 1).to_s
row.save!
return next_card_number
end
結果:効果なし
レガシー コード + with_lock
CardValue.with_lock do
row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
next_card_number = row.value
row.value = (next_card_number.to_i + 1).to_s
row.save!
return next_card_number
end
結果: with_lock が定義されていないというエラー
レガシー コード + with_lock
CardValue.transaction do
lock!
row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
next_card_number = row.value
row.value = (next_card_number.to_i + 1).to_s
row.save!
return next_card_number
end
結果:ロックが定義されていないというエラー