掲題を実現する場合のサンプル。
処理で更新されるテーブルのモデルに、以下のようなメソッドを実装。
class BatchExecUpdateDate < ApplicationRecord # batch_exec_update_dates # # id :bigint(8) not null, primary key # proc_type :integer not null # upated_at :datetime not null enum proc_type : { daily: 0, monthly: 1} class << self def transaction_with_lock(proc_type, &block) target_rec = find_or_create_by(proc_type: proc_type) ActiveRecord::Base transacrion do # 行ロック取得 lock_rec = BatchExecUpdateDate.lock('FOR UPDATE NOWAIT').find(target_rec.id) # 引数で渡されたブロックを処理する block.call lock_rec.update(updated_at: Time.zone.now) end true rescue ActiveRecord::StatementInvalid => e return false if e.cause&.kind_of?(PG::LockNotAvailable) raise e end end end
modelでupdate_atを必須valideteかけている場合は、
明示的にupdated_atをセットしないとエラーになる
validate指定を外すと、自動でセットしてcreateしてくれる
validates :updated_at, presence: true target_rec = find_or_create_by(proc_type: proc_type) {|beud| beud.updated_at = Time.zone.now}
以下のような処理があったとして
# 処理クラス class AaaBatch class << self def update_process # 更新処理 end end end
以下のように呼び出すことで、実現できる。
# 起動するとき BatchExecUpdateDate.transaction_with_lock(proc_type) do AaaBatch.update_process(0) BbbBatch.update_process(0) : end