php定时任务必须用绝对路径调用php解释器并显式切换项目目录,如0 /3 cd /var/www/myproject && /usr/bin/php think cron:clean-cache >> /var/log/clean-cache.log 2>&1,配合flock加锁防并发,再通过crontab -l、手动执行和系统日志三步验证生效。

PHP本身没有内置定时能力,所有“定时任务”本质都是靠操作系统级的 crontab 触发 PHP 命令行脚本——框架只是帮你把逻辑包装成可调用的命令,不是它自己在后台守时钟。
crontab 调用 PHP 命令必须用绝对路径
直接写 php think xxx 或 php artisan xxx 在 crontab 里大概率静默失败。因为 crontab 的环境变量极简,不读取你的 shell profile,$PATH 里通常没有 php。
- 先在终端执行
which php,记下输出,比如/usr/bin/php或宝塔环境下的/www/server/php/84/bin/php - 所有
crontab条目里,PHP 解释器必须写这个绝对路径,不能省略 - 同时,
cd切换到项目根目录也必须显式写出,否则自动加载器、配置文件、日志路径全都会错位
Laravel 的 schedule:run 只需一条 crontab 规则
别手痒去给每个任务单独配 crontab 行——Laravel 的调度设计就是只靠一条固定规则驱动整个调度系统。
- 正确写法:
* * * * * cd /var/www/laravel-app && /usr/bin/php artisan schedule:run >> /dev/null 2>&1 - 这条命令每分钟执行一次,但真正跑哪个任务、什么时候跑,全由
app/Console/Kernel.php中的schedule()方法决定 - 如果改成
*/5 * * * *(每5分钟),就可能漏掉->everyMinute()这类任务,框架不会补跑
ThinkPHP 自定义命令要手动注册并显式调用
ThinkPHP 没有 Laravel 那样的集中调度入口,每个命令都得单独被 crontab 调用,且必须确保命令已注册、命名规范、路径无误。
- 命令类放在
app/command/目录,继承think\console\Command,configure()中用setName('xxx:yyy')定义命令名 -
crontab中调用格式为:0 3 * * * cd /var/www/myproject && /usr/bin/php think xxx:yyy >> /var/log/xxx.log 2>&1 - 如果命令没生效,先运行
php think list确认该命令是否出现在可执行列表中;没出现说明类没被自动扫描到,检查命名空间和文件路径是否匹配
加 flock 锁防止并发是生产环境刚需
服务器负载高或 crontab 时间粒度粗时,同一任务可能被重复拉起多个进程,轻则日志混乱,重则数据库连接打满、缓存被清空两次、邮件重复发送。
- 推荐用
flock -n加锁:* * * * * cd /var/www/myproject && flock -n /tmp/mytask.lock -c '/usr/bin/php think my:task >> /var/log/mytask.log 2>&1' -
-n表示非阻塞,如果锁已被占用,当前这次直接跳过,不会卡住或堆积进程 - 锁文件路径必须是全局唯一且可写,
/tmp/下最稳妥;别用__DIR__动态生成锁路径,crontab下工作目录不可靠
最容易被忽略的是时区和日志重定向:系统时区、PHP CLI 时区、crontab 解析时间用的时区,三者不一致就会导致任务“明明设了凌晨2点,结果下午2点才跑”;而没加 >> /path/to.log 2>&1,失败时连错误信息都看不到,只能干瞪眼。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











