定时任务未触发应先检查调度链路:1. 运行php artisan schedule:list确认任务是否注册;2. 手动执行php artisan schedule:run查看实时输出与报错;3. 配置cron日志并检查Laravel自身日志。

定时任务没触发,先别急着改代码——90% 的问题出在调度链路没通,而不是逻辑写错了。核心要确认两件事:调度定义是否被识别、系统是否真在每分钟调用 schedule:run。查看调度列表和日志,是最快定位卡点的方式。
用 schedule:list 快速验证任务是否注册成功
这个命令不执行任务,只列出 Laravel 当前“看到”的所有已注册调度项,是判断 schedule() 方法是否生效的第一步。
- 在项目根目录下运行:
php artisan schedule:list - 正常输出应包含类似这样的表格:每行一个任务、计划时间(Cron 表达式)、描述、下次运行时间
- 如果提示 "No scheduled commands are ready to run" 或直接为空,说明调度未注册成功——最常见原因是把
schedule()方法写在了App\Http\Kernel里,而不是App\Console\Kernel - 顺便检查命令是否已注册:运行
php artisan list,确认你用$schedule->command('xxx')调用的命令名出现在列表中
手动运行 schedule:run 查看实时输出
这是模拟系统 cron 的行为,能立刻知道当前时刻有哪些任务该跑、有没有报错。
- 执行:
php artisan schedule:run - 若任务符合当前时间条件(比如设了
->everyMinute()或正好到整点),会显示类似 Running scheduled command: app:send-report - 如果没输出任何 “Running” 行,但
schedule:list又有内容,说明时间条件不匹配(比如写了->dailyAt('09:00'),现在是下午一点) - 如果有报错(如类找不到、数据库连接失败),会直接打印在终端,比查日志更快定位依赖问题
配置 cron 日志,让每次调用都有迹可循
服务器 cron 默认不记录输出,一旦失败就静默跳过。必须显式重定向日志,否则等于“盲调”。
- 编辑 crontab:
crontab -e - 把原来这行:
* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1
改成带日志路径的版本,例如:* * * * * cd /var/www/myapp && /usr/bin/php artisan schedule:run >> /var/log/laravel-schedule.log 2>&1 - 注意使用绝对路径的 PHP(
which php查),并确保/var/log/目录对 cron 用户(如 www-data)有写权限 - 之后用
tail -f /var/log/laravel-schedule.log实时观察每分钟 cron 是否真的触发、输出是否正常、有没有 Permission denied 或 Class not found 类错误
检查 Laravel 自身日志里的调度上下文
有些错误不会出现在 cron 日志里,但会进 Laravel 的 storage/logs/laravel-*.log,尤其是闭包任务或命令 handle() 中抛出的异常。
- 在你的命令
handle()方法开头加一行:\Log::info('MyCommand started at ' . now()); - 或在闭包里也加日志:
$schedule->call(function () { \Log::info('Ping from scheduler'); })->everyMinute(); - 然后查
storage/logs/laravel-$(date +%Y-%m-%d).log,确认日志是否写入——没写入说明根本没走到那一步;写入了但后续报错,就顺着日志往下追 - 特别注意:闭包内抛出未捕获异常会导致整个
schedule:run进程中断,后续任务全部跳过,且默认不进 Laravel 日志,所以务必在闭包里自己加try/catch











