Rails には、クレジット カードに請求される金融取引を表すトランザクション モデルがあります。
トランザクションが作成されると、そのステータスは になり:new
ます。(DelayedJob で発生する) 料金を決済しようとすると、ステータスを に更新します:pending
。charge
status が でない場合、以降の呼び出しは無視されます:new
。
単純なバージョン (同時実行性には関係ありません):
# Trigger a card to be charged
def charge_transaction
return unless status == :new
self.transaction do
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
# Actually do the charging (in a delayed worker)
def settle_credit_card
# ... Interact with our payment gateway
end
これは load_balanced Web アプリであるため、同時実行を考慮し、(同時要求による) 重複料金を作成しないようにしたいと考えています。私は楽観的ロックの利点を理解していますが、この場合、課金 (または何らかの方法でトランザクションを更新) を同時に試みることは例外的なケースであるため、この重要な領域を持つことは気にしません。
これは、悲観的な行レベルのロックを使用する試みです
同時バージョン (オプション 1)
# Trigger a card to be charged
def charge_transaction
# Obtain row-lock
self.with_lock do
self.reload # Reload once lock is obtained - necessary?
# Check status after lock/reload
return unless status == :new
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
同時バージョン (オプション 2)
# Trigger a card to be charged
def charge_transaction
# Begin transaction without lock
self.transaction do
self.reload(lock: true) # Reload and obtain lock
# Check status after lock/reload
return unless status == :new
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
これらのアプローチのいずれか (または両方) は有効ですか? ロックを取得したら (トランザクション オブジェクトが最新であることを確認するために) 明示的なリロードが必要ですか、それともロックを取得するときに Rails は自動的にそれを行いますか? 両方のアプローチが有効である場合、どちらが望ましいですか?
どうもありがとう!