laravel 12任务调度本身不提供调度器超时控制,超时保护应作用于被调度的artisan命令或队列任务:命令需自行实现超时逻辑,队列任务可通过$timeout属性或--timeout参数设限,并用withoutoverlapping防止重叠执行。

Laravel 12 任务调度本身不直接提供“调度任务超时”控制(比如限制 schedule:run 执行时间),但生产环境中真正需要防超时的,是调度所触发的**具体命令或队列任务**。关键在于分清两层:调度器(driver)只负责按时“唤醒并派发”,而超时保护必须落在被调度的实体上——即 Artisan 命令本身,或它内部 dispatch 的队列 Job。
对 Artisan 命令设置执行超时
如果你在 app/Console/Kernel.php 中通过 $schedule->command('backup:run') 调度一个自定义命令,该命令若可能卡住(如数据库导出、远程 API 等待),应在命令类中主动设限:
- 在命令类(如
app/Console/Commands/BackupRun.php)里,重写handle()方法,并用 PHP 原生信号或超时检测逻辑包裹耗时操作; - 更稳妥的做法是:将实际工作逻辑移入队列任务,再让命令仅负责 dispatch,把超时控制下放到 Job 层——这是 Laravel 推荐的解耦方式。
对队列任务设置超时(推荐主用)
绝大多数耗时操作应走队列。Laravel 12 沿用并强化了任务级超时机制,支持两种粒度:
-
任务类内声明:在 Job 类中定义
protected $timeout = 180;(单位秒),表示该任务最多运行 3 分钟,超时后会被强制终止并标记为失败; -
队列监听器全局约束:启动 worker 时加
--timeout=120参数,例如:php artisan queue:work --timeout=120 --max-jobs=100;注意此值需 ≤ 任务自身的$timeout,否则任务可能在被框架检测前就被系统 kill。
防止调度重叠导致“伪超时”
某些任务执行时间波动大(如定时同步外部数据),若上一次还没结束,下一次又被调度器触发,看起来像“永远跑不完”。这不是超时问题,而是并发冲突:
- 在
schedule()中为该任务链式调用withoutOverlapping(); - 它会自动在缓存中打标(默认用 cache 驱动),确保同一任务不会重复启动;
- 可选配
preventOverlappingFor($seconds)控制锁有效期,避免因异常退出导致锁残留。
额外建议:监控与兜底
光靠超时不够,还需可观测性:
- 启用
failed_jobs表,配合php artisan queue:failed-table和queue:listen日志,快速定位哪些任务频繁超时; - 对关键调度任务,添加
onFailure()回调,触发告警或清理动作; - 若使用 Coolify 或类似平台,确认其
schedule:work进程由 s6-overlay 等进程管理器守护,避免调度器自身崩溃后无人拉起。











