タスクマネージャーであるアプリケーションが1つあります。
各ユーザーは、自分に割り当てる新しいタスクを選択できます。
2人のユーザーが同時に同じタスクを受け入れる場合、同時実行の問題はありますか?
私のコードは次のようになります。
if @user.task == nil
@task.user = @user
@task.save
end
2人の異なるユーザーの場合、2台の異なるマシンでこのURLを同時に開きます。問題がありますか?
タスクマネージャーであるアプリケーションが1つあります。
各ユーザーは、自分に割り当てる新しいタスクを選択できます。
2人のユーザーが同時に同じタスクを受け入れる場合、同時実行の問題はありますか?
私のコードは次のようになります。
if @user.task == nil
@task.user = @user
@task.save
end
2人の異なるユーザーの場合、2台の異なるマシンでこのURLを同時に開きます。問題がありますか?
楽観的ロックを使用して、他の「古い」レコードがデータベースに保存されないようにすることができます。lock_version
これを有効にするには、モデルにデフォルト値が。の列が必要です0
。
レコードがデータベースからフェッチされると、電流lock_version
がそれに伴います。レコードが変更されてデータベースに保存されると、データベースの行は、レコードがフェッチされたときに存在していたを制約することUPDATE
により、条件付きで更新されます。lock_version
変更されていない場合は、UPDATE
がインクリメントされますlock_version
。変更された場合、更新は何も行わず、例外(ActiveRecord::StaleObjectError
)が発生します。次のようにオフにしない限り、これはActiveRecordのデフォルトの動作です。
ActiveRecord::Base.lock_optimistically = false
(オプションで)以外の列名を使用できますlock_version
。カスタム名を使用するには、モデルクラスに次のような行を追加します。
set_locking_column :some_column_name
楽観的ロックの代わりに、データベースレベルでのテーブルレベルまたは行レベルのロックに依存する悲観的ロックがあります。このメカニズムは、ロックされた行へのすべてのアクセスをブロックするため、パフォーマンスに悪影響を与える可能性があります。
試したことはありませんが、http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.htmlを使用できます。
次のような特定のタスクのロックを取得できるはずです。
@task = Task.find(some_id)
@task.with_lock do
#Then let's check if there's still no one assigned to this task
if @task.user.nil? && @user.task.nil?
@task.user = @user
@task.save
end
end
繰り返しになりますが、私はこれを使用したことがないのでsleep
、ロックの内側を大きくしてテストし、実際にすべてが希望どおりにロックされることを確認します
また、ここについてはよくわかりませんreload
。行がロックされているため、失敗する可能性があります。ただし、ロックを取得した後、オブジェクトがデータベースから新鮮であることを確認する必要があります。これを行う別の方法がある場合があります。
EDit:リロードする必要はありwith_lock
ません。ソースコードをチェックして、あなたに代わって行います。
https://github.com/rails/rails/blob/4c5b73fef8a41bd2bd8435fa4b00f7c40b721650/activerecord/lib/active_record/locking/pessimistic.rb#L61