Laravel失败任务默认不进failed_jobs表,需手动启用失败日志功能;重试耗尽后才归档,$tries属性优先级高于命令行参数;exception字段为空多因异常不可序列化;归档后可通过queue:retry重试,但依赖记录存在且配置正确。

队列失败任务默认不进 failed_jobs 表?
不是 Laravel 没这功能,是它默认关着——failed_jobs 表只在你显式启用失败日志时才写入。Laravel 6+ 默认使用 database 驱动时,也得手动运行迁移并配置开关,否则失败任务直接丢弃,连日志都看不到。
常见错误现象:php artisan queue:work 报错后任务消失,failed_jobs 表空,storage/logs/laravel.log 里只有堆栈没归档痕迹。
- 必须先执行
php artisan queue:failed-table+php artisan migrate - 确认
config/queue.php中'failed'配置项已启用,例如:'database'或'redis'(Redis 需额外装laravel/framework≥9.25 支持) - 环境变量
QUEUE_FAILED_DRIVER优先级高于配置文件,别被它覆盖
queue:work 不重试就进失败表?
不会。Laravel 默认失败归档前会先重试——重试次数耗尽后才落库。这个“耗尽”由两个地方控制:命令行参数和任务类自身的 $tries 属性,后者优先级更高。
使用场景:你想让某个发邮件任务最多试 1 次失败就归档,而不是默认的 3 次;或者临时调试想跳过重试直接进表。
- 在任务类里设
public $tries = 1;,比全局配置更精准 - 启动 worker 时加
--tries=1对所有任务生效,但无法区分任务粒度 - 注意:如果用了
retryUntil(),它会覆盖$tries,且时间戳过期才算失败 - 重试间隔(
$backoff)不影响归档时机,只影响重试等待时长
失败表字段里 exception 是空的?
大概率是异常没被正确捕获或序列化失败。Laravel 把整个 Exception 实例 serialize() 后存进 exception 字段,而某些对象(比如带闭包、资源句柄、未实现 __serialize 的自定义异常)会静默失败,导致字段为空字符串或 null。
性能影响:空 exception 让排查退回到翻日志,失去失败表的核心价值。
- 避免在异常中携带不可序列化内容(如
Request、Response、数据库连接) - 自定义异常类务必实现
__serialize()和__unserialize(),或继承Exception基类(PHP 8.1+) - 临时验证:在任务
handle()里throw new \Exception('test');,看是否正常入库 - MySQL 字段类型要是
longtext,别用text截断异常堆栈
归档后还能重试?queue:retry 不起作用?
能重试,但前提是失败记录还在 failed_jobs 表里,且没被清理。不起作用的常见原因是:表被清空了、记录被 queue:flush 删除、或用了非默认连接(比如多数据库时 failed 配置指向了错误的 DB)。
容易踩的坑:本地开发用 SQLite,生产用 MySQL,但 config/queue.php 里 'failed' => ['database' => 'sqlite'] 没切环境,导致失败记录写到本地文件,线上完全看不到。
- 查记录是否存在:
DB::table('failed_jobs')->where('id', 123)->first() - 重试单条:
php artisan queue:retry 123;重试全部:php artisan queue:retry all - 重试后原记录不会删,而是生成新 job 进队列,原
failed_jobs行保留failed_at时间戳 - 别依赖
queue:forget清理——它只是删失败记录,不解决根本问题
真正麻烦的是异常里混了请求上下文或临时文件路径,这种归档进去也没法复现;归档只是兜底,不是替代日志和监控。


















