90%定时任务不执行是因crontab未正确配置,必须添加 * cd /var/www/myapp && /usr/bin/php artisan schedule:run >> /dev/null 2>&1,确保路径、php绝对路径、时区及命令类注册准确。

定时任务跑不起来,90% 的问题出在 crontab 没配对,而不是 Laravel 代码写错了。
crontab 必须每分钟调用 schedule:run,且路径和 PHP 版本要精准
系统级 cron 是 Laravel 调度器的“启动开关”,缺它,schedule() 里写的任何逻辑都不会触发。
-
crontab -e中必须添加这一行(不能只写php artisan schedule:run):* * * * * cd /var/www/myapp && /usr/bin/php artisan schedule:run >> /dev/null 2>&1 -
cd后的路径必须是 Laravel 项目根目录,漏掉或写错会导致artisan找不到 autoload 或配置文件 -
/usr/bin/php要和which php输出一致;如果服务器装了多个 PHP 版本(如php7.4),必须显式写全路径,否则可能用错版本导致类找不到 -
>> /dev/null 2>&1不可省略:没有重定向,cron 会因输出缓冲阻塞后续执行,尤其在日志满或权限不足时静默失败
Kernel::schedule() 里用闭包容易失效,优先走命令类
闭包看似简洁,但在 Laravel 5.5 的调度上下文中极易出问题——它不共享命令生命周期,也不自动注入依赖。
- 闭包内不能用
$this->info()、$this->warn()等 Artisan 方法,因为没绑定命令实例 -
$this->someService这类属性访问会报Undefined property,因为闭包执行时Kernel尚未完成构造或依赖未解析 - 真正要用闭包,必须手动通过
app()解析:$schedule->call(function () { app(MyService::class)->doWork(); })->everyMinute(); - 异常默认静默:闭包里抛错不会进 Laravel 日志,务必包
try/catch并显式Log::error() - 调试困难:无法单测、无法复用、无法查看参数类型——复杂逻辑一律封装进
App\Console\Commands\*类
本地调试别等时间,用 schedule:list 和临时频率验证通路
php artisan schedule:run 在本地不跑任务,不是 bug,是设计如此:它严格比对当前时间与定义的时间表达式(比如 dailyAt('02:00')),不匹配就跳过。
- 运行
php artisan schedule:list查看所有任务的下次运行时间,重点核对两处:
—Next Due是否符合预期
— 时区是否和config/app.php中的'timezone'一致(Laravel 调度完全依赖该配置,不读系统时区) - 调试阶段把
->daily()临时改成->everyMinute(),确认逻辑能跑通再换回真实频率 - 执行
php artisan schedule:run --verbose可看到“哪些任务被跳过”及原因(例如 “Not due yet” 或 “No scheduled commands are ready to run”) - 避免在
handle()里写阻塞操作(如大文件读取、无超时 cURL),否则会拖慢整个调度周期,导致后续任务堆积或被跳过
命令类注册和签名必须匹配,$commands 数组在 Laravel 5.5 中仍需手动维护
Laravel 5.5 不支持自动发现命令类,Kernel 中的 $commands 属性是硬性注册入口,漏写就调不动。
- 创建命令后,必须在
app/Console/Kernel.php的$commands数组中加入完整命名空间:protected $commands = [\App\Console\Commands\MyTask::class]; -
$signature属性决定命令名,必须和schedule()->command('xxx')中的字符串完全一致:
若设为protected $signature = 'my:task';,调度里就得写$schedule->command('my:task')->daily(); - 签名里带参数(如
my:task {id})时,调度中必须传参:$schedule->command('my:task 123')->daily();—— 注意空格分隔,不能用数组 - 命令类构造函数里用依赖注入没问题,但确保对应服务已绑定到容器(比如
AppServiceProvider中$this->app->bind(...)),否则schedule:run会报Target [Interface] is not instantiable
最常被忽略的是时区配置和 $commands 注册——这两处一错,任务连调度器的门都摸不到。











