在給客戶做二開的時候增加了一個抽獎類型,最后客戶發現如果頻繁點擊理解請求會出現多次請求的實際返回一個的中獎信息問題,經過排查測試發現原本程序的積分抽獎功能也存在,然后做了一下優化,增加了一個鎖進行限制,然后發現解決問題了。
解決方法:
1.修改app/services/activity/lottery/LuckLotteryServices.php 文件中的 public function luckLottery(int $uid, int $lottery_id) 方法代碼,增加如下代碼:
// 使用更嚴格的鎖機制
$lockKey = 'lottery_lock_' . $uid . '_' . $lottery_id;
$cache = CacheService::redisHandler();
// 增加日志,記錄請求信息
Log::info('開始抽獎,檢查鎖', [
'uid' => $uid,
'lottery_id' => $lottery_id,
'lockKey' => $lockKey,
'exists' => $cache->get($lockKey),
'time' => date('Y-m-d H:i:s'),
'request_id' => uniqid()
]);
// 先嘗試設置鎖
$isLocked = $cache->setnx($lockKey, 1);
// 如果設置失敗,說明鎖已存在
if (!$isLocked) {
Log::info('抽獎鎖已存在,禁止重復抽獎', [
'uid' => $uid,
'lottery_id' => $lottery_id,
'time' => date('Y-m-d H:i:s'),
'request_id' => uniqid()
]);
throw new ValidateException('抽獎處理中,請勿重復點擊');
}
// 設置成功后設置過期時間
$cache->expire($lockKey, 120);
try {
} catch (\Exception $e) {
$cache->delete($lockKey);
throw $e;
} finally {
// 釋放鎖前記錄日志
Log::info('抽獎完成,釋放鎖', [
'uid' => $uid,
'lottery_id' => $lottery_id,
'exists' => $cache->get($lockKey),
'time' => date('Y-m-d H:i:s'),
'request_id' => uniqid()
]);
$cache->delete($lockKey);
}
自己看這截圖 及代碼 自己修改,當然我不確定其他版本有這個問題,我這邊客戶使用的是3.0.1版本。
修改完以后記得重啟swoole,并且代碼如果正常生效會輸出出來響應的日志如:
[2024-12-12T15:41:28+08:00][info] 開始抽獎,檢查鎖
[2024-12-12T15:41:28+08:00][info] 抽獎鎖已存在,禁止重復抽獎
[2024-12-12T15:41:32+08:00][info] 開始抽獎,檢查鎖
[2024-12-12T15:41:32+08:00][info] 抽獎鎖已存在,禁止重復抽獎
[2024-12-12T15:41:37+08:00][info] 開始抽獎,檢查鎖
[2024-12-12T15:41:37+08:00][info] 抽獎鎖已存在,禁止重復抽獎
[2024-12-12T15:42:11+08:00][info] 開始抽獎,檢查鎖
[2024-12-12T15:42:11+08:00][info] 抽獎鎖已存在,禁止重復抽獎
[2024-12-12T15:45:39+08:00][info] 開始抽獎,檢查鎖
[2024-12-12T15:45:39+08:00][info] 抽獎完成,釋放鎖