并发任务失败不重试是因为Laravel默认不为Batch或并行子任务自动注入$tries,需每个任务类显式定义public $tries;重试需手动在failed()中dispatch并延时,注意反序列化限制与payload完整性。

并发任务失败后默认不重试,必须显式配置 $tries 或使用 withBackoff() 等机制,否则直接进 failed_jobs 表——这不是 Bug,是 Laravel 的设计前提。
为什么并发任务失败后根本没重试?
很多人在用 dispatch(new Job)->allOnQueue('high') 或 Bus::batch() 时发现失败任务没重试,本质是因为:Laravel 的自动重试只作用于单个 Job 实例,而并发场景(如 Batch、Chunk、多任务并行分发)中,框架不会为每个子任务自动注入 $tries,除非你在每个任务类里单独定义。
-
Bus::batch([...])->dispatch()中的每个任务,仍需各自声明public $tries = 3;,否则失败即终止 - 使用
dispatch(new Job)->onQueue('high')->delay(now()->addSeconds(5))并发推入,但没设$tries→ 失败后不重试,只写表 - 在
handle()里用collect($items)->each(fn($i) => dispatch(new ProcessItem($i))),每个ProcessItem若没定义$tries,就等于“只跑一次” - Batch 任务本身(
BatchJob)不支持$tries,它的失败回调finally()或catch()里必须手动重试子任务,不能依赖框架兜底
并发任务中怎么让某类错误秒级重试?
别依赖全局 $backoff 数组,它对瞬态网络错误太慢;要精准控制,得在 failed() 里主动重发,并配合 Redis 的毫秒级延迟能力。
- 确保队列驱动是
redis(database不支持毫秒delay) - 在任务类中设
public $tries = 1;,避免框架默认重试干扰你的逻辑 - 在
failed(\Exception $exception)方法里判断异常类型:if ($exception instanceof ConnectException || $exception instanceof TimeoutException) - 满足条件时调用
dispatch($this)->onQueue($this->queue)->delay(now()->addMilliseconds(200)); - 注意:不要在
failed()里调用retry()或重复dispatch(new static(...)),会丢失原始$job->id和中间件上下文
Batch 批量任务失败后如何选择性重试?
Batch 本身不重试,但你可以基于 failedJobs 列表做条件过滤,只重试可恢复的子任务,而不是全量重跑。
- 监听
BatchFailed事件,在回调中获取$event->batch->failedJobs数组 - 遍历每个失败 ID,查
failed_jobs表的exception字段,用str_contains($exception, 'Connection refused')做简单分类 - 对匹配的 ID,执行
Artisan::call('queue:retry', ['id' => $id]);,跳过唯一索引冲突等不可重试错误 - 若用了自定义连接(如
redis),记得加--queue=redis参数,否则可能连错连接 - 慎用
php artisan queue:retry all:Batch 场景下极易引发重复扣款、重复通知等副作用
并发重试时最容易被忽略的反序列化问题
重试不是“再跑一遍”,而是从 failed_jobs.payload 反序列化重建对象——这个过程在并发任务里更容易失败。
- Payload 超过 MySQL TEXT 字段长度(65535 字节)会被截断,重试时报
unserialize(): Error at offset;改用LONGTEXT或切到 Redis 驱动 - 任务里引用了
$request、UploadedFile、闭包或资源句柄(如cURLhandler)→ 反序列化必然失败,重试永远卡住 - 并发分发时用了
use ($var)捕获大数组或对象,导致 payload 膨胀 → 查看failed_jobs.payload字段实际长度,别只看代码逻辑 - Horizon Web 界面显示 “Retry” 按钮是假的——它只是调用
queue:retry命令,不校验 payload 是否完整,点了可能白忙


















