diff --git a/application/common/QueueJob.php b/application/common/QueueJob.php index a334a27..87462de 100644 --- a/application/common/QueueJob.php +++ b/application/common/QueueJob.php @@ -212,39 +212,55 @@ class QueueJob */ public function acquireLock($sRedisKey, $sRedisValue, $job) { - $isLocked = $this->QueueRedis->startJob($sRedisKey, $sRedisValue, $this->lockExpire); - - if (!$isLocked) { - $currentLockValue = $this->QueueRedis->getRedisValue($sRedisKey); // 获取当前锁值 - $jobStatus = $this->QueueRedis->getJobStatus($sRedisKey); - - // 若锁值为空或过期,强制抢占锁 - if (empty($currentLockValue) || $jobStatus === false) { - $this->log("数据为空 | 状态: {$currentLockValue} | 键: {$jobStatus}"); - $isLocked = $this->QueueRedis->startJob($sRedisKey, $sRedisValue, $this->lockExpire); - if ($isLocked) return true; - } - if (in_array($jobStatus, ['completed', 'failed'])) { - $this->log("任务已完成或失败,删除任务 | 状态: {$jobStatus} | 键: {$sRedisKey}"); - $job->delete(); - } else { - $attempts = $job->attempts(); - if ($attempts >= $this->maxRetries) { - $this->log("超过最大重试次数({$this->maxRetries}),停止重试 | 键: {$sRedisKey}"); - $job->delete(); - } else { - $lockTtl = $this->QueueRedis->getLockTtl($sRedisKey); - $delay = $lockTtl > 0 ? $lockTtl + 5 : 30; - // 限制最大延迟时间 - $delay = min($delay, $this->maxDelay); - $this->log("锁竞争,{$delay}秒后重试({$attempts}/{$this->maxRetries}) | 键: {$sRedisKey}"); - $job->release($delay); - } - } + // 1. 前置校验:先检查是否已完成/失败(优先于锁操作) + $jobStatus = $this->QueueRedis->getJobStatus($sRedisKey); + if (in_array($jobStatus, ['completed', 'failed'])) { + $this->log("任务已终止,删除任务 | 键: {$sRedisKey} | 状态: {$jobStatus}"); + $job->delete(); return false; } - $this->log("写入成功 | 状态: {$sRedisKey} | 键: {$sRedisValue}"); - return true; + + // 2. 尝试获取锁 + $isLocked = $this->QueueRedis->startJob($sRedisKey, $sRedisValue, $this->lockExpire); + if ($isLocked) { + $this->log("成功获取锁 | 键: {$sRedisKey} | 锁值: {$sRedisValue}"); + return true; + } + + // 3. 锁竞争处理:二次校验状态+超时抢占 + $currentLockValue = $this->QueueRedis->getRedisValue($sRedisKey); + $jobStatus = $this->QueueRedis->getJobStatus($sRedisKey); + + // 3.1 若状态已终止,直接删除任务 + if (in_array($jobStatus, ['completed', 'failed'])) { + $this->log("任务已终止,删除任务 | 键: {$sRedisKey} | 状态: {$jobStatus}"); + $job->delete(); + return false; + } + + // 3.2 锁已过期(值为空或TTL<=0),强制抢占 + $lockTtl = $this->QueueRedis->getLockTtl($sRedisKey); + if (empty($currentLockValue) || $lockTtl <= 0) { + $this->log("锁已过期,强制抢占 | 键: {$sRedisKey} | TTL: {$lockTtl}"); + $isLocked = $this->QueueRedis->startJob($sRedisKey, $sRedisValue, $this->lockExpire); + if ($isLocked) { + return true; + } + } + + // 3.3 未获取到锁,按重试策略处理 + $attempts = $job->attempts(); + if ($attempts >= $this->maxRetries) { + $this->log("超过最大重试次数({$this->maxRetries}),删除任务 | 键: {$sRedisKey}"); + $job->delete(); + } else { + // 动态计算延迟时间(基于当前锁剩余时间) + $delay = $lockTtl > 0 ? $lockTtl + 5 : 30; + $delay = min($delay, $this->maxDelay); + $this->log("锁竞争,延迟{$delay}秒重试({$attempts}/{$this->maxRetries}) | 键: {$sRedisKey}"); + $job->release($delay); + } + return false; } /**