laravel 11不支持跨任务原生依赖调度,需显式实现:一、a成功后直接分发b;二、数据库状态表标记完成并轮询校验;三、redis原子信号协调;四、job batching的then回调触发汇总任务。

Laravel 11 本身不支持跨任务的原生依赖调度,比如“定时任务 A 执行完,再自动触发定时任务 B”——调度器只负责按时间触发任务,不管执行结果或前后顺序。所以“任务依赖”必须靠显式设计逻辑来实现,而不是靠 schedule() 方法自动串联。
下面几种方式在 Laravel 11 中稳定可用,按推荐程度和适用场景排列:
直接在任务 A 中分发任务 B
适合 A 和 B 耦合紧密、B 必须等 A 成功完成且能拿到其输出的场景。
- 在 A 的 Artisan 命令
handle()方法末尾调用:dispatch(new ProcessInvoiceReport($invoiceId))->onQueue('high'); - 确保 A 执行成功(没抛异常)后才触发 B;若 A 失败,B 不会进入队列。
- 注意:B 接收的参数必须可序列化,不能传
$this->app或数据库连接实例。
使用数据库状态表做完成标记
适合 A 和 B 完全解耦、可能分属不同服务器、需失败重试与可观测性的场景。
- 创建
task_status表,含字段:task_type(如'invoice_generation')、target_id、status(pending/completed/failed)、updated_at。 - A 执行完毕后更新对应记录为
completed。 - B 在
handle()开头检查:if (! DB::table('task_status') ->where('task_type', 'invoice_generation') ->where('target_id', $this->invoiceId) ->where('status', 'completed') ->exists()) { $this->release(120); // 延迟 2 分钟重试 return; } - 配合
$tries = 5和日志告警,避免无限等待。
利用 Redis 原子信号协调
适合高并发、低延迟、不想压数据库的场景。
- A 结束时写入:
Redis::setex("task:invoice:{$this->invoiceId}:done", 7200, '1'); - B 启动时读取:
if (! Redis::get("task:invoice:{$this->invoiceId}:done")) { $this->release(60); return; } - 可选加
BLPOP实现轻量等待,但一般轮询+重试更稳。
用 Job Batching(Laravel 11 原生支持)
如果你的任务 A 实际是批量处理(比如处理 100 条订单),且 B 是汇总或通知类操作,这是最干净的方案。
- 在 A 的调度中启动批处理:
Bus::batch([ new ProcessOrder($order1), new ProcessOrder($order2), // ... ])->then(function (Batch $batch) { dispatch(new SendBatchSummary($batch->id)); })->dispatch(); -
then()回调会在所有子任务成功完成后触发,天然带依赖与错误传播。
不建议的做法:
- ❌ 在
schedule()里用->after($jobA)或dispatchAfterResponse—— 这些不适用于定时任务,也不感知执行结果。 - ❌ 在 B 里循环
sleep(1)等待 A 写库 —— 极易耗尽连接、触发超时、干扰队列吞吐。
本质上,Laravel 11 的调度器仍是「时间驱动」,不是「事件驱动」。依赖关系得由你定义状态、传递信号、控制流程——代码写清楚了,逻辑就稳了。











