最常见任务“卡住”原因是已入队但无人消费,应先查jobs表中reserved_at为空的待处理任务,再结合attempts、created_at等字段判断积压原因;failed_jobs表为空可能因未启用失败记录功能;reserved_at不为空但任务未完成则可能是worker意外终止导致超时重试。

直接查 jobs 表看有没有待处理任务
任务“卡住”最常见原因是已入队但没人消费,jobs 表就是第一现场。打开 phpMyAdmin,选中 Laravel 所用数据库,找到 jobs 表(若没这张表,说明 QUEUE_CONNECTION=database 但没运行 php artisan queue:table)。
执行 SQL 查询:
SELECT id, queue, attempts, reserved_at, created_at FROM jobs WHERE reserved_at IS NULL ORDER BY created_at LIMIT 20;
这条语句筛选出所有「尚未被 worker 拿走」的任务——也就是真正积压的待处理任务。重点关注:
-
attempts值为 0:刚入队,正常 -
attempts> 0 且reserved_at为空:之前尝试过但失败后又放回队列,可能反复重试失败 -
created_at很老但一直没被消费:worker 进程根本没在跑,或队列名配错(比如代码里用onQueue('notifications'),但jobs表里queue字段是default)
failed_jobs 表里查不到记录?先确认是否启用失败记录
很多人在 phpMyAdmin 里搜 failed_jobs 表,发现空空如也,就以为“没失败”。其实更可能是根本没启用失败记录功能。
立即学习“PHP免费学习笔记(深入)”;
检查三件事:
- 表是否存在:若不存在,说明没运行
php artisan queue:failed-table && php artisan migrate -
config/queue.php中'failed' => ['driver' => 'database']是否配置(Redis 驱动默认不写这个表,必须显式设) -
.env中QUEUE_CONNECTION值是否拼错(比如写成database_name而非database),导致整个队列降级为sync,连jobs表都不进,更别说failed_jobs
如果表存在但数据为空,再查 jobs 表里 attempts 达到最大重试次数(如 3)却仍没进 failed_jobs,大概率是 failed 配置项未生效,或任务里用了 try/catch 吞掉了异常。
从 failed_jobs 表看失败详情时别只读 exception 字段
failed_jobs.exception 字段存的是序列化后的异常对象,直接在 phpMyAdmin 里点开看到的是乱码或一长串字符,几乎无法阅读。
正确做法是导出整行记录,用 PHP 反序列化查看:
$row = DB::table('failed_jobs')->where('id', 123)->first();
var_dump(unserialize($row->exception));
或者更简单:在 Laravel 中用命令行查,它会自动格式化:
php artisan queue:failed
如果非得在 phpMyAdmin 看,可临时加一列存可读信息——在任务的 failed() 方法里手动写日志:
Log::error('Job failed', [
'job' => get_class($this),
'trace' => $exception->getTraceAsString(),
'message' => $exception->getMessage()
]);
这样日志文件里就能对应上 failed_jobs.id,比硬啃序列化字段靠谱得多。
reserved_at 不为空但任务没完成?可能是 worker 意外终止
在 jobs 表里发现一堆 reserved_at 有值、attempts 却没变、created_at 是几小时前的记录——这是典型的「worker 拿走了任务,但进程崩了或被 kill,没来得及释放或标记完成」。
这种任务会被 Laravel 自动视为「超时」,等 retry_after(默认 90 秒)过去后,worker 下次拉取时会重新把它当新任务处理(attempts +1)。但如果你改过 retry_after 或用了 --timeout 参数,而实际任务执行时间超过该值,就会陷入无限重试循环。
排查建议:
- 检查
config/queue.php中对应连接的retry_after值(Database 驱动)或block_for(Redis)是否合理 - 确认 worker 启动命令是否带了
--timeout=120之类参数,且大于任务实际耗时 - 查服务器日志:
journalctl -u supervisor或supervisorctl tail laravel-worker stderr,找 segfault、OOM killer 杀进程等线索
这类问题不会在 failed_jobs 表体现,因为任务根本没走到“抛异常”那步,而是被系统强制中断。所以光盯失败表,会漏掉一大块真实故障。



















