laravel调度器本身不提供失败重试或记录机制,失败处理需由被调度命令或队列任务自行实现;推荐将耗时操作转为队列任务以利用其失败处理、重试和监控能力。

Laravel 任务调度(schedule)本身不内置失败重试或失败记录机制——它只是按计划调用 Artisan 命令或闭包,真正的失败处理需落在被调度的命令或队列任务上。换句话说:调度器不会捕获异常,也不会自动重试;失败处理必须由被调度的目标逻辑承担。
明确失败发生的位置
调度任务失败通常分两类场景:
-
Artisan 命令执行失败:比如
php artisan users:notify在 handle() 中抛出未捕获异常,进程退出但无日志、无通知、不重试 -
调度中分发的队列任务失败:例如在
schedule()里调用ProcessReport::dispatch()->delay(now()->addMinutes(5)),该队列任务后续执行失败,则走队列的失败处理流程(failed_jobs表、failed()方法等)
给调度命令加基础容错
在自定义 Artisan 命令的 handle() 方法中主动捕获异常并记录:
- 用
try/catch包裹核心逻辑,写入日志(Log::error()) - 可配合 Laravel 通知系统发送告警,例如失败时触发 Slack 通知
- 避免命令静默失败:不要让异常直接冒泡到顶层,否则 cron 只看到“非零退出码”,无上下文
把耗时/易错操作转为队列任务
这是最推荐的做法。调度器只负责“发起”,不负责“执行”:
- 在
App\Console\Kernel.php的schedule()方法中,用$schedule->job(new SendDailyDigest)->daily();替代$schedule->command('digest:send')->daily(); - 这样失败会进入队列失败系统:自动记录到
failed_jobs表、触发JobFailed事件、支持failed()自定义处理、可用queue:retry手动恢复 - 还能利用
$tries、retryAfter()等机制实现指数退避重试
监控调度是否按时触发
调度器自身可能“失联”,比如 Cron 未配置、supervisor 挂掉、服务器时间异常:
- 在
schedule()中添加心跳日志:$schedule->command('log:schedule-ping')->everyMinute();,定期写入一条时间戳,用于判断调度器是否存活 - 用外部监控(如 Prometheus + cURL probe)检查某个健康端点,该端点返回最近一次调度日志时间
- 对关键任务加超时兜底:例如每日报表任务,若凌晨 3 点还没完成,另一个定时任务在 4 点检查并触发告警











