在给客户做二开的时候增加了一个抽奖类型,最后客户发现如果频繁点击理解请求会出现多次请求的实际返回一个的中奖信息问题,经过排查测试发现原本程序的积分抽奖功能也存在,然后做了一下优化,增加了一个锁进行限制,然后发现解决问题了。
解决方法:
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] 抽奖完成,释放锁