laravel任务调度依赖“一个系统cron+一个php调度器”,只需配置一条crontab,所有定时任务必须在app/console/kernel.php的schedule()方法中声明;支持command()调用artisan命令或call()执行闭包逻辑。

Laravel 任务调度不是靠多个 cron 条目,而是靠「一个系统 cron + 一个 PHP 调度器」协同工作。你只需要在服务器上配一条 crontab,所有定时逻辑都写在 app/Console/Kernel.php 的 schedule() 方法里 —— 这是核心前提,错这一步,后面全白搭。
怎么在 Kernel.php 里注册任务
所有任务必须在 app/Console/Kernel.php 的 schedule() 方法中声明,不能散落在别处。Laravel 不会自动扫描命令或 Job 类来触发调度。
-
$schedule->command('backup:database')->dailyAt('02:00'):调用已注册的 Artisan 命令,推荐用于封装完整业务逻辑(如备份、清理) -
$schedule->call(function () { DB::table('logs')->where('created_at', 'subDay())->delete(); })->hourly():适合轻量、无复用需求的内联逻辑,但别塞太多代码,否则难测试、难维护 -
$schedule->job(new SendWelcomeEmail($user))->weeklyOn(1, '09:00'):分发队列任务,前提是该 Job 实现了ShouldQueue接口 - 注意时区:默认用服务器本地时区,若需统一(比如全按
Asia/Shanghai),必须显式加->timezone('Asia/Shanghai'),否则线上和本地开发时间对不上
为什么 crontab 配置总不生效
最常见原因是路径或环境变量缺失 —— crontab 默认不加载你的 shell profile(~/.bashrc 或 ~/.zshrc),所以 php 命令可能找不到,APP_ENV 可能是 local 而非 production。
- 务必用绝对路径调用 PHP:比如
/usr/bin/php或/opt/homebrew/bin/php,而不是裸写php - 确保项目路径正确:
cd /var/www/myapp && /usr/bin/php artisan schedule:run,路径错一个字符就静默失败 - 输出别全丢进
/dev/null:调试阶段改成>> /var/log/laravel-schedule.log 2>&1,能看到真实错误(比如「Class not found」或「Connection refused」) - 检查权限:运行 cron 的用户(通常是
www-data或daemon)必须对storage/logs和storage/framework/cache有写权限,否则日志、缓存全挂
如何防止任务重复执行或堆积
默认情况下,如果前一次任务还没跑完,下一次 cron 触发时它仍会尝试启动 —— 对数据库清理、文件导出这类长耗时任务很危险。
- 加
->withoutOverlapping()是最简单有效的防护,Laravel 会在cache中设锁,自动跳过重叠调用 - 对关键任务(如支付结算),建议再叠加
->onOneServer(),避免多台机器部署时重复触发(依赖缓存驱动支持原子操作) - 慎用
->evenInMaintenanceMode():除非真需要,否则维护模式下停掉定时任务更安全,避免干扰上线流程 - 用
php artisan schedule:list(Laravel 8.73+)确认任务注册是否成功、下次执行时间是否符合预期,比盲猜强得多
真正容易被忽略的不是语法,而是环境一致性:cron 用户的 PATH、PHP 版本、.env 加载顺序、时区设置 —— 这些细节不拉平,schedule:run 就像在黑盒里跑,成功靠运气,失败没日志。











