TP6队列任务执行失败需排查入队、消费及闭环处理,核心是配置、进程、驱动对齐;必须禁用sync驱动,改用redis/database并正确配置host/port/database、retry_after;消费者须用Supervisor常驻管理;Job类需设tries、记录日志、处理失败;生产环境应切failed存储至Redis、清理失败任务、关键任务改用RabbitMQ。

TP6队列任务执行失败,不能只看“报错不报错”,重点要排查任务是否真正入队、是否被消费、失败后有没有闭环处理。常见问题不是代码写错了,而是配置、进程、驱动三者没对齐。
确认队列驱动已切换为异步模式
默认的 sync 驱动会让任务同步执行(无日志、无延迟、无法重试),表面成功实则没走队列流程:
- 检查
config/queue.php中'default' => 'redis'(或'database'),不能是'sync' - Redis 驱动必须显式配置三项:
'host'、'port'、'database'(注意:旧版'select'已废弃) -
'retry_after'值需大于任务最长执行时间(如发短信耗时 8 秒,此处至少设为 10)
确保消费者进程已启动且持续运行
调用 Queue::push() 只是把任务写入 Redis 或数据库,不会自动触发执行:
- 手动运行监听命令:
php think queue:work --queue=default --daemon(加--daemon才是常驻模式) - 生产环境务必用 Supervisor 管理,配置中
autostart=true和autorestart=true缺一不可 - Supervisor 的
command必须用绝对路径,例如:/usr/bin/php /var/www/tp6/think queue:work --daemon
在 Job 类中规范处理失败逻辑
任务执行出错时,不捕获异常会导致任务直接丢弃;不控制重试次数会引发雪崩:
- 每个 Job 类定义
public $tries = 3;,框架会自动限制最大重试次数 - 在
fire()方法内主动判断:if ($job->attempts() >= 3) { // 记录告警或推送到死信队列 } - 消费失败必须记录日志:
Log::error('OrderJob failed', ['id' => $data['id'], 'attempts' => $job->attempts()]); - Redis 延迟队列场景下,push 失败要重试(如网络抖动),可用 while 循环 + 指数退避
生产环境必备的容错补丁
万级并发下,光靠默认配置扛不住,需主动加固:
- 将失败任务存储从数据库切到 Redis:
'failed' => ['type' => 'redis'],避免failed_jobs表锁表 - 设置
retry_after≥stopwaitsecs(Supervisor 配置项),防止平滑重启时任务被重复消费 - 每日定时清理:
php think queue:flush清空已确认失败的任务,防止堆积 - 关键任务(如支付回调)改用 RabbitMQ 驱动,开启消息持久化与 ACK 确认机制











