laravel调度钩子是绑定在单个任务上的回调函数,非全局监听器;onsuccess/onfailure需配合sendoutputto才能捕获结果,before/after运行在调度器进程内,pingbefore/pingafter为http请求,非任务内部事件。

调度钩子不是“注册完就自动生效”的监听器,而是绑定在单个调度任务上的回调函数,只对那个任务起作用;用错位置或混淆执行时机,会导致日志没写、通知漏发、甚至任务重复触发。
onSuccess / onFailure 必须配合 sendOutputTo 才能稳定捕获结果
这两个钩子依赖任务进程的退出码和标准输出,如果没配置输出重定向,Laravel 无法判断命令是否真正成功。
-
onSuccess()只在命令返回 exit code 0 且 stdout 中没有报错内容时触发,但默认不保存 stdout -
sendOutputTo()把输出写入文件后,onFailure()才能读取失败堆栈并决定是否发邮件 - 常见错误:写了
->onFailure(...)却没加->sendOutputTo(...),结果永远不触发 - 示例写法:
$schedule->command('backup:run')->daily()->sendOutputTo(storage_path('logs/backup.log'))->onFailure(function () { \Mail::to('admin@example.com')->send(new BackupFailed()); });
before / after 钩子运行在调度器进程内,不是任务本身上下文
它们在 schedule:run 命令执行前后调用,和被调度的 Artisan 命令、闭包、队列任务是分离的进程,不能共享数据库连接或事务状态。
-
before()在检查所有任务是否到期前执行,适合做全局准备(如预热缓存、检查磁盘空间) -
after()在本次schedule:run完全结束时执行,适合清理临时文件、上报统计 - 不能在里面调用
DB::transaction()或修改 Eloquent 模型——那些操作不会影响后续被调度的任务 - 如果你需要“任务执行前/后”逻辑,应该把逻辑写进命令类的
handle()方法里,而不是调度钩子
pingBefore / pingAfter 要求目标服务支持 HTTP HEAD 或 GET 并返回 2xx
这两个钩子本质是发 HTTP 请求,不是 Laravel 内部事件,失败不会中断任务,但容易因超时或响应格式不对而静默失效。
-
pingBefore()发请求后才执行任务,若目标不可达,任务会被跳过(Laravel 默认超时 10 秒) -
pingAfter()是异步非阻塞的,即使请求失败,任务也已完成 - 常见坑:监控平台要求带特定 header 或 token,但
pingAfter('https://mon.example.com/ping')不支持传参,得改用thenPing()+ 自定义 Guzzle 客户端 - 调试方法:临时加
->then(function () { \Log::info('task finished'); })确认任务真跑完了,再排查 ping 是否超时
钩子的执行顺序和生命周期容易被当成“任务生命周期的一部分”,其实它只是调度器的一次性回调;真正要控制任务内部行为,优先用命令类自身的 handle() 和异常处理,钩子只适合做轻量、外部、可观测的操作。











