Sidekiq建議所有作業都是冪等的(能夠多次運行而不會成爲問題),因爲它無法保證作業只能運行一次。使用Sidekiq Ruby on Rails的冪等設計作業
我無法理解在某些情況下實現該目標的最佳方法。例如,假設你有如下表:
用戶 ID 電子郵件 平衡
是簡單地運行後臺作業增加了一定量的資產負債
def perform(user_id, balance_adjustment)
user = User.find(user_id)
user.balance += balance_adjustment
user.save
end
如果作業運行他們的餘額不止一次會不正確。什麼是這樣的最佳做法?
如果我想成爲一個潛在的解決方案,我可以想出是安排這就是說,
PendingBalanceAdjustment USER_ID balance_adjustment
作業運行時,它需要在作業之前創造紀錄爲該用戶獲取鎖定,以便兩個工作人員之間不存在競爭狀況的機會,然後在釋放鎖定之前需要更新餘額並從未決餘額調整中刪除該記錄。
那麼這份工作看起來像這樣?
def perform(user_id, balance_adjustment_id)
user = User.find(user_id)
pba = PendingBalanceAdjustment.where(:balance_adjustment_id => balance_adjustment_id).take
if pba.present?
$redis.lock("#{user_id}/balance_adjustment") do
user.balance += pba.balance_adjustment
user.save
pba.delete
end
end
end
這似乎解決兩個
兩名工人正在作業的同時(雖然你會覺得Sidekiq已經可以保證這一點?) B)作業正在運行之間一)競爭條件成功運行多次後
這種模式是一個很好的解決方案嗎?
嘿!感謝您的即時迴應。我可以將平衡調整和掛起行刪除放入數據庫事務中,但是這並不一定能夠防止多線程併發問題,其中兩名工作人員都嘗試同時運行事務嗎? –
對於每一項與此類似的工作,必須要有某種類型的PendingABC記錄,這看起來似乎有點矯枉過正/很多開銷。這真的是最好的模式嗎? –
通常有一個跟蹤每個貨幣調整歷史的信用/借記表。 「user.balance」列只是成爲sum(PBA.amount)的緩存副本。我會使用SQL而不是Ruby來自動完成這些事情。單個UPDATE語句比Ruby中的多個網絡調用快得多/可靠。 –