要允许用户创建余额提取请求,我有一个WithdrawalsController#create
操作。在继续创建提款之前,代码会检查用户是否有足够的余额。
def create
if amount > current_user.available_balance
error! :bad_request, :metadata => {code: "002", description: "insufficient balance"}
return
end
withdrawal = current_user.withdrawals.create(amount: amount, billing_info: current_user.billing_info)
exposes withdrawal
end
这可能会在多线程服务器中造成严重问题。当两个创建请求同时到达,并且两个请求都在创建提款之前通过了余额检查,那么即使两个总和可能超过原始余额,也可以创建两个提款。
具有Mutex
的类变量将不是一个好的解决方案,因为这将为所有用户锁定此操作,其中需要锁定每个用户级别。
最佳解决方案是什么?
答案 0 :(得分:1)
据我所知,你的代码在这里是安全的,多线程并不是一个很大的问题。即使您的应用服务器生成了更多应用实例,每个实例也会最终测试amount > current_user.available_balance
。
如果你真的很妄想它。你可以用transacaction
包裹所有人:
ActiveRecord::Base.transaction do
withdrawal = current_user.withdrawals.create!(
amount: amount,
billing_info: current_user.billing_info
)
# if after saving the `available_balance` goes under 0
# the hole transaction will be rolled back and any
# change happened to the database will be undone.
raise ActiveRecord::Rollback if current_user.available_balance < 0
end