ThinkPHP 6 队列重试需同时满足三条件:任务类中 public $maxTries 和 public $retryAfter 属性有效、使用 database 或 redis 驱动、通过 php think queue:work 常驻运行且真实抛出异常。

ThinkPHP 6 队列重试机制失效,不是代码写错了,而是几个关键点没对齐——maxTries没生效、retryAfter被忽略、驱动或启动方式不支持重试,三者缺一不可。
maxTries 必须是 public 属性且未被覆盖
重试次数由任务类自己控制,框架不读配置文件里的 maxTries。
- ✅ 正确写法:
public $maxTries = 3;(必须是public) - ❌ 错误写法:
private $maxTries = 3;或在config/queue.php里加'maxTries' => 3(完全无效) - ⚠️ 命令行参数会强制覆盖:
php think queue:work --tries=1会让$maxTries = 3彻底失效
retryAfter 控制失败后入队延迟,不是首次延迟
它只在任务抛出异常、且重试条件满足时起作用。
-
public $retryAfter = 5;表示失败后等 5 秒再重新入队(单位:秒) - ❌ 不要和
delay()混用:$this->delay(5)是首次执行前延迟,跟重试无关 - ❌
retryAfter = 0.1容易引发高并发下密集重入,建议不低于 2 秒
驱动和启动方式决定重试是否真正发生
- ✅ 支持重试的驱动只有
database和redis(sync驱动完全无视重试) - ✅
php think queue:work默认支持重试(需确保进程常驻) - ❌
php think queue:work --once只执行一次就退出,不触发任何重试逻辑 - ❌
php think queue:listen已废弃,不维护 attempts 计数,重试行为不可靠
异常必须真实抛出,返回 false 不触发重试
- ✅
throw new Exception('发送失败');→ 触发重试 - ❌
return false;或静默exit;→ 任务被标记为完成,不重试也不进 failed_jobs - 建议在
handle()最外层加try-catch,手动记录日志并确保异常透出
Redis 驱动下还要注意消费端清理
TP6 的 Redis 队列不会自动删除已消费任务:
- 如果
handle()执行成功但忘了调用$job->delete(),下次 worker 还会取出来再执行一遍(看起来像重复,其实是没删) - 如果执行失败又没
throw异常,只是return或exit,任务就卡在 list 里,既不重试也不进 failed
基本上就这些。

















