定时任务不执行的根源是服务器未配置Cron或配置错误;需检查crontab路径、PHP绝对路径、项目目录权限、cron服务状态、时区一致性、withoutOverlapping()与onOneServer()锁机制。

确认系统 Cron 是否真在运行 schedule:run
90% 的「定时任务不执行」问题,根源是服务器上压根没配 Cron,或者配了但命令根本没跑起来。别急着查代码,先看服务器层面:
- 运行
crontab -e,检查是否存在类似这行(注意路径和 PHP 可执行文件必须是绝对路径):* * * * * cd /var/www/myapp && /usr/bin/php artisan schedule:run >> /dev/null 2>&1 - 不能写
php—— 生产环境常无 alias,/usr/bin/php或/opt/plesk/php/8.1/bin/php才可靠 - 确保
cd /var/www/myapp中的路径是项目真实根目录,且当前用户有执行权限 - 用
systemctl status cron(或systemctl status crond)确认 cron 服务正在运行
手动触发 schedule:run 看输出是否正常
这是最直接的验证方式:在项目根目录下执行
php artisan schedule:run
观察输出:
- 如果有
Running scheduled command: ...,说明调度器本身能识别任务,问题大概率出在 Cron 没调它 - 如果报错如
Class 'App\Console\Commands\BackupCommand' not found,说明命令类注册或命名空间有误 - 如果完全没输出、或提示
No scheduled commands are ready to run,检查app/Console/Kernel.php中schedule()方法是否真的注册了任务,且时间条件未被跳过(比如设了dailyAt('03:00'),但当前是晚上 22 点)
检查 Laravel 调度器是否被时区搞乱
Laravel 默认用 APP_TIMEZONE(如 UTC),而系统 Cron 按服务器本地时区解析时间。两者不一致会导致「明明写了 dailyAt('06:00') 却从不执行」。
- 运行
date查服务器当前时间与时区 - 检查
.env中APP_TIMEZONE=Asia/Shanghai是否与你期望的执行时间匹配 - 更稳妥的做法:统一设为
UTC,并在schedule()中用->timezone('Asia/Shanghai')显式指定任务时区,例如:$schedule->command('reports:daily')->dailyAt('06:00')->timezone('Asia/Shanghai');
验证任务是否被 withoutOverlapping() 或 onOneServer() 拦住
这两个修饰符不会报错,但会让任务静默跳过,极易被忽略:
-
withoutOverlapping():上一次执行还没结束,本次就会直接跳过。用php artisan schedule:list看状态列是否显示Overlapping disabled,再查缓存(Redis/Memcached)里是否有对应锁键(如scheduled:xxx)残留 -
onOneServer():多机部署时,只有抢到缓存锁的那台会执行。若只有一台服务器却仍不执行,检查CACHE_DRIVER是否配置为redis或memcached(不能是file或array) - 临时注释掉这两个链式调用,再手动运行
schedule:run测试是否恢复
真正卡住的地方往往不是语法错误,而是路径、时区、缓存锁、权限这四类「看不见的依赖」。每次排查优先验证 crontab -e 输出 + php artisan schedule:run 实际响应,比翻代码快得多。


















