队列任务超时后会被直接丢弃,不是暂停或重试;Laravel中timeout超时会强制终止进程且不触发重试,retryUntil()比tries更可控,数据库驱动下failed_jobs写入失败会导致任务丢失。

队列任务超时后会被直接丢弃,不是暂停或重试
默认情况下,Laravel 队列任务一旦超过 timeout 设置(默认 60 秒),Worker 就会强制终止该进程,且不触发重试——哪怕你配置了 tries。这是最常被误解的一点:超时 ≠ 失败,它属于“被杀死”,不会进入失败队列,也不会自动重试。
实操建议:
- 超时值必须大于任务实际最长耗时,建议在本地压测出 P95 耗时后再加 20% 缓冲
- 不要依赖超时来“兜底重试”,要用
retryUntil()或显式抛异常触发重试逻辑 - 如果任务含阻塞操作(如
sleep()、同步 HTTP 请求、大文件处理),务必拆解或改用异步方式,否则极易触发超时
Laravel 9+ 中 retryUntil() 比 tries 更可控
tries 是固定次数重试,但长任务失败时间点不可控;retryUntil() 允许你指定一个绝对截止时间(\DateTimeInterface),更适合定时类、时效敏感型长任务。
示例:一个最多运行到明天凌晨 2 点的任务
public function retryUntil()
{
return now()->addHours(24)->startOfHour()->addHours(2);
}
注意点:
-
retryUntil()仅在任务抛出未捕获异常时生效;静默失败(如 return false)不会重试 - 时间戳需早于队列 Worker 启动时间,否则视为已过期,任务直接丢弃
- 与
timeout独立计算:即使timeout=300,只要在retryUntil()时间前没成功,就会按策略重入队列
数据库驱动下,failed_jobs 表写入失败会导致重试丢失
使用 database 驱动时,任务失败后需先写入 failed_jobs 表,再决定是否重试。若此时数据库连接中断、磁盘满或表结构异常,Laravel 会静默跳过记录和重试,任务彻底消失。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
规避方法:
- 上线前确认
failed_jobs表存在且可写,字段uuid和connection索引已建好 - 避免在
handle()中手动调用DB::transaction()包裹整个逻辑——失败回滚可能连带干掉队列自身的事务 - 生产环境优先用
redis或supervisor+horizon,它们对失败链路更健壮
php artisan queue:work --timeout=3600 的 timeout 是全局硬限制
命令行启动 Worker 时传的 --timeout 参数,会覆盖任务类里定义的 $timeout 属性,且无法被运行时动态修改。这意味着:即使你在任务里写了 ini_set('max_execution_time', 0),也拦不住 Laravel 自己的超时杀进程逻辑。
关键细节:
- 该 timeout 是从
handle()方法开始执行起计时,不含反序列化、中间件、日志初始化等开销 - 超时后进程 SIGKILL,不会执行
__destruct(),资源(如临时文件、Redis 连接)可能残留 - 多个 Worker 共享同一配置时,务必统一设置,否则部分实例可能提前终止长任务
复杂点在于:超时判定发生在 PHP 进程外部(由 Laravel 的 Worker 类控制),你没法用 pcntl_signal 捕获或优雅降级。能做的只有预估、分段、监控和告警。










