Php Laravel-防止多个请求同时创建重复记录
我有一个取消订单的方法,退款给用户 但是,使用API,如果用户对同一记录调用端点两次(在循环中),则会向用户退款两次。如果我一次尝试3次Api调用,前2次请求得到退款,第3次请求没有Php Laravel-防止多个请求同时创建重复记录,php,laravel,eloquent,deadlock,Php,Laravel,Eloquent,Deadlock,我有一个取消订单的方法,退款给用户 但是,使用API,如果用户对同一记录调用端点两次(在循环中),则会向用户退款两次。如果我一次尝试3次Api调用,前2次请求得到退款,第3次请求没有 public function cancelOrder($orderId) { // First I tried to solve with cache, // but it is not fast enough to catch the loop if (Cache::has("ap
public function cancelOrder($orderId) {
// First I tried to solve with cache,
// but it is not fast enough to catch the loop
if (Cache::has("api-canceling-$orderId")) {
return response()->json(['message' => "Already cancelling"], 403);
}
Cache::put("api-voiding-$labelId", true, 60);
// Here I get the transaction, and check if 'transaction->is_cancelled'.
// I thought cache will be faster but apparently not enough.
$transaction = Transaction::where('order_id', $orderId)
->where('user_id', auth()->user()->id)
->where('type', "Order Charge")
->firstOrFail();
if ($transaction->is_cancelled) {
return response()->json(['message' => "Order already cancelled"], 403);
}
// Here I do the api call to 3rd party service and wait for response
try {
$result = (new OrderCanceller)->cancel($orderId);
} catch (Exception $e) {
return response()->json(['message' => $e->getMessage()], 403);
}
$transaction->is_cancelled = true;
$transaction->save();
// This is the operation getting called twice.
Transaction::createCancelRefund($transaction);
return response()->json(['message' => 'Refund is made to your account']);
}
createCancelReturn()
方法如下所示:
public static function createCancelRefund($transaction) {
Transaction::create([
'user_id' => $transaction->user_id,
'credit_movement' => $transaction->credit_movement * -1,
'type' => "Order Refund"
]);
}
我尝试过的事情:
- 将
方法中的所有内容包装到cancelOrder()
闭包中。(也尝试了DB::transaction({},5)
方法)DB::beginTransaction()
- 在
上使用$transaction=transaction::where('order\u id',$orderId)
->lockForUpdate()。。。询问
- 将
内容包装在createcancelreturn()
中,但我认为这对DB::transaction({},5)
没有帮助create()
- 尝试使用缓存,但速度没有那么快
- 查看了节流功能,但它似乎不能防止这种情况(如果我说2个请求/分钟,则仍然会发生重复创建)
createcancelreturn()中防止重复退款创建的正确方法是什么?解决了我的问题
原子锁允许在不担心竞争条件的情况下操纵分布式锁。例如,Laravel Forge使用原子锁来确保一次只在服务器上执行一个远程任务
您必须有一些全局(ie DB)条目来存储退款状态。因此,如果退款已经退款,则在第二次请求时不执行任何操作您没有从语句Cache::lock(“api取消-{$orderId}”)->get(函数()use($orderId)返回{
您确定您的代码在发生错误时返回响应吗success@hhsadiq你让我意识到,如果锁关闭中有一个bug,它会崩溃,它会永远锁定。你有什么策略可以更好地处理这个问题吗?所以我们解释说它非常好,它会处理这种情况以避免永远锁定。我们已经实现了他推荐的方法,今天将上线。让我们看看它在生产中是如何工作的:-)
public function cancelOrder($orderId) {
return Cache::lock("api-canceling-{$orderId}")->get(function () use ($orderId) {
$transaction = Transaction::where('order_id', $orderId)
->where('user_id', auth()->user()->id)
->where('type', "Order Charge")
->firstOrFail();
if ($transaction->is_cancelled) {
return response()->json(['message' => "Order already cancelled"], 403);
}
try {
$result = (new OrderCanceller)->cancel($orderId);
} catch (Exception $e) {
return response()->json(['message' => $e->getMessage()], 403);
}
$transaction->is_cancelled = true;
$transaction->save();
// This is the operation getting called twice.
Transaction::createCancelRefund($transaction);
return response()->json(['message' => 'Refund is made to your account']);
});
return response()->json(['message' => "Already cancelling"], 403);
}