Laravel的Bus::batch()是开箱即用的批量任务方案,但需满足三条件:Laravel≥8.5、队列驱动为database或redis、每个Job类引入Batchable trait;缺一则job_batches表不写入、无batch_id、回调不触发。

直接说结论:Laravel 的 Bus::batch() 是开箱即用的批量任务解决方案,但必须满足三个硬性条件——Laravel ≥ 8.5、队列驱动为 database 或 redis、每个 Job 类都用了 Batchable trait。漏掉任一条件,job_batches 表就不会写入,前端查不到进度,回调也不触发。
为什么 Bus::batch() 调用了却没生成 batch_id?
最常见原因是队列驱动配置错误或 Job 缺少关键 trait:
-
QUEUE_CONNECTION=sync时Bus::batch()会静默降级为同步执行,不入库、无batch_id,必须改用database或redis - Job 类没引入
Illuminate\Bus\Batchabletrait,会导致该 Job 在批次中无法被识别为可批处理任务,整个 Batch 构建失败(但不会报错) - 调用了
->dispatch()但队列工作进程未运行,job_batches表只在 dispatch 时写入初始状态,不启动 worker 就永远卡在pending_jobs = total_jobs
如何安全地在 Job 中获取当前批次状态?
不能依赖全局变量或外部查询,必须通过 $this->batch() 实例方法获取实时状态:
- Job handle() 内必须先检查
if (! $batch = $this->batch()) { return; },因为重试或手动 dispatch 可能脱离批次上下文 -
$batch->progress()返回的是整数百分比(0–100),不是小数;$batch->finishedJobs和$batch->totalJobs是原始属性,需自行计算 - 不要在
failed()方法里直接调用$this->batch()—— 失败时批次对象可能已被清理,应改用catch回调统一处理
前端轮询 job_batches 表时要注意什么?
查表本身很简单,但字段语义和更新时机容易误读:
-
pending_jobs包含「尚未开始」和「正在执行中」的任务,不是纯待办数;真正空闲的 worker 数量需结合 Horizon 或php artisan queue:work --status判断 -
failed_job_ids是 JSON 字符串,不是数组,PHP 中要用json_decode($batch->failed_job_ids, true)解析,直接遍历会出错 - 字段更新有延迟:Redis 驱动下通常
- 不要用
where('status', 'finished')查完成批次——状态字段是finished(无下划线),且finally回调执行完才置为该值
最易被忽略的一点:Batch 的 timeout() 默认是 24 小时,但这个超时是从 dispatch() 开始计时,不是从第一个 Job 执行起算。如果一批任务本身要跑 25 小时(比如超大文件分片处理),必须显式调用 ->timeout(90000),否则未完成的 Job 会被框架标记为失败并终止后续执行。


















