必须使用Bus::batch()构造批次并满足三条件:Laravel≥8.5、QUEUE_CONNECTION为database或redis、Job类use Batchable;否则$batch->id为空且job_batches表无记录。

要在Laravel 8中真正实现异步任务的批量调度与状态可控执行,必须绕过直接调用dispatch()的陷阱,用Bus::batch()构造具备元数据追踪能力的批次,并确保每个Job能被独立消费——否则看似发出去了,实际连job_batches表都不会写入一条记录。
确认基础环境是否达标
先验证三个硬性条件是否全部满足,缺一不可:【Laravel ≥ 8.5】、【QUEUE_CONNECTION 必须是 database 或 redis】、【所有 Job 类必须 use Illuminate\Bus\Batchable】。如果用sync驱动,Bus::batch()会静默降级为同步执行,$batch->id为空,后续所有回调失效,且job_batches表无任何写入。
检查.env:QUEUE_CONNECTION=database(或redis);运行php artisan queue:table生成jobs和job_batches表(database驱动必需);打开任意Job类,确认顶部已声明use Illuminate\Bus\Batchable;
编写支持批处理的Job类
在Job类中引入Batchable trait并启用队列契约:
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessUserData implements ShouldQueue { use Batchable, Queueable, SerializesModels; }
这一步漏掉Batchable,整个批次构建失败但不报错——你只会发现$batch->id始终为null,日志里也找不到线索。
handle()方法内可直接通过$this->batch()获取当前批次实例,例如记录进度:$this->batch()->progress($this->batch()->totalJobs(), $this->batch()->finishedJobs() + 1);
构造并分发批次任务
方法一:基础分发带回调
use Illuminate\Support\Facades\Bus;
$jobs = [new ProcessUserData($user1), new ProcessUserData($user2), new ProcessUserData($user3)];
$batch = Bus::batch($jobs)
→ then(fn ($batch) => \Log::info('全部完成', ['id' => $batch->id]))
→ catch(fn ($batch, $e) => \Log::error('某任务失败', ['id' => $batch->id, 'err' => $e->getMessage()]))
→ finally(fn ($batch) => \Log::debug('收尾动作', ['id' => $batch->id]))
→ dispatch();
注意:dispatch()调用后立即返回$batch对象,此时$batch->id已生成,可用于前端轮询或存入session,但任务尚未开始执行。
方法二:动态生成大批量Job(避免内存溢出)
当要处理5000条用户数据时,别一次性new 5000个对象塞进数组——PHP可能OOM。改用foreach分块构造:
$jobs = [];
foreach (User::cursor() as $user) {
$jobs[] = new ProcessUserData($user);
if (count($jobs) >= 100) {
Bus::batch($jobs)->dispatch();
$jobs = [];
}
}
if (!empty($jobs)) { Bus::batch($jobs)->dispatch(); }
启动并发消费者
第一步:确保队列服务已运行,且连接的是database或redis驱动;
第二步:启动多个worker进程,命令需明确指定队列连接与并发数:
php artisan queue:work database --concurrent=4
或使用Supervisor管理多进程,每条进程对应一个queue:work实例——这才是真正的并发消费。单个queue:work进程无论怎么优化,都只能串行处理任务,无法发挥批次优势。
第三步:观察jobs表新增记录数量应等于$jobs数组长度,job_batches表有且仅有一条对应记录,batch_id字段非空。


















