fix: 修复并发竞态与幂等性缺陷并优化子树查询
Some checks failed
lotterLaravel CI / test (push) Has been cancelled

- 扩大玩家ID随机数位宽降低碰撞概率
- 授信额度变更加 lockForUpdate 防并发下调
- 结算冲正与入账利用唯一索引实现幂等闸门
- 失败登录计数加锁防丢失
- 代理子树查询改用子查询替代全表 pluck
- 修复返点默认值百分比单位转换
- 测试中全量 fake 广播事件防 CI 500
This commit is contained in:
2026-06-18 09:38:24 +08:00
parent 2e0b257160
commit 6b2ea39ea1
13 changed files with 400 additions and 135 deletions

View File

@@ -6,6 +6,7 @@ use App\Lottery\ErrorCode;
use App\Models\Player;
use App\Support\PlayerAuthSource;
use Firebase\JWT\JWT;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use App\Exceptions\PlayerAuthenticationException;
@@ -114,15 +115,31 @@ final class PlayerNativeAuthService
{
$max = (int) config('lottery.player_auth.native.max_login_attempts', 8);
$lockMinutes = (int) config('lottery.player_auth.native.lock_minutes', 15);
$count = (int) $player->login_failed_count + 1;
$updates = ['login_failed_count' => $count];
if ($count >= $max) {
$updates['login_locked_until'] = now()->addMinutes($lockMinutes);
$updates['login_failed_count'] = 0;
}
// 并发场景下两个错误登录请求都拿到旧 login_failed_count 各自 +1 时,会出现 last-write-wins
// 丢失一次失败计数(影响锁定判定准确性)。用 lockForUpdate 取最新计数后再写。
\DB::transaction(function () use ($player, $max, $lockMinutes): void {
$latest = Player::query()
->whereKey((int) $player->id)
->lockForUpdate()
->first();
$player->forceFill($updates)->save();
if ($latest === null) {
return;
}
$count = (int) $latest->login_failed_count + 1;
$updates = ['login_failed_count' => $count];
if ($count >= $max) {
$updates['login_locked_until'] = now()->addMinutes($lockMinutes);
$updates['login_failed_count'] = 0;
}
Player::query()
->whereKey((int) $player->id)
->update($updates);
});
}
/**