laravel 10调度器本身不提供失败重试或回调,失败处理需落在被调度的具体任务上:调度命令应内置异常捕获与日志记录;关键任务宜转为队列任务以利用队列的自动重试、failed()方法和failed_jobs表管理;配合withoutoverlapping()防重叠执行,并结合外部监控实现告警。

Laravel 10 的任务调度器(Scheduler)本身不直接提供任务失败重试或失败回调机制,它只负责按时间规则触发命令或闭包。真正执行任务的是 Artisan 命令或队列任务——而失败处理需落在被调度的“具体任务”层面,不是 Scheduler 层能统一拦截的。
所以,设置任务失败处理的关键在于:把调度对象设计成可容错、可监控、可恢复的单元。以下是实际有效的做法:
调度命令需自带异常捕获与日志记录
被 schedule() 调用的 Artisan 命令(如 php artisan report:generate)应在 handle() 方法中主动包裹异常处理:
public function handle()
{
try {
// 执行核心逻辑:生成报表、写入数据库等
$this->generateReport();
} catch (\Exception $e) {
\Log::error('定时报表任务失败', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
// 可选:发送告警(邮件、钉钉、企业微信)
Notification::route('mail', 'ops@example.com')
->notify(new ScheduledTaskFailed($e));
}
}
这样即使命令崩溃,也能留下完整上下文,便于排查。
将高频/关键调度任务转为队列任务
避免在 schedule() 中直接调用耗时或易失败的操作。改用「调度 + 队列」组合:
protected function schedule(Schedule $schedule)
{
// 每天凌晨2点,分发一个队列任务(非同步阻塞执行)
$schedule->call(function () {
dispatch(new GenerateDailyReportJob());
})->daily()->at('02:00');
}
此时失败处理就交给 Laravel 队列系统:
- 自动重试(通过
tries=3或retryAfter=60控制) - 最终失败时触发
failed()方法(可清理资源、发通知) - 记录到
failed_jobs表,支持php artisan queue:failed查看
使用 withoutOverlapping() 防止失败叠加
如果前一次任务未结束(比如卡死、超时),下一次又被调度,可能引发并发冲突或数据错乱。加锁可避免雪球效应:
$schedule->command('sync:orders')
->everyFiveMinutes()
->withoutOverlapping(); // 同一任务最多一个实例运行
配合 runInBackground() 或 onOneServer() 还能进一步限制执行节点。
配合健康检查与外部监控
Laravel 调度器没有内置失败告警,但你可以:
- 在命令末尾写成功标记(如
touch storage/app/last-report-success),用脚本定期检测该文件是否过期 - 使用第三方服务(如 Healthchecks.io):在命令开头
curl -s https://hc-ping.com/xxx/start,结尾再 ping 一次完成 - 在服务器 Cron 日志中 grep
schedule:run的 stderr 输出,配合 logrotate 做异常聚合
不复杂但容易忽略











