根本原因是crontab进程默认关闭STDIN且未重定向stdout/stderr,导致PHP异常或SIGTERM信号静默退出;须强制重定向日志、开启错误报告、注册SIGTERM处理器并统一使用绝对路径。

crontab 执行的 PHP 脚本中途退出,没报错也没日志?
根本原因不是脚本写错了,而是 crontab 启动的进程默认不继承终端会话,STDIN 关闭、stdout/stderr 未重定向,PHP 进程一旦遇到未捕获异常或被系统信号(如 SIGTERM)中断,就静默退出,连错误堆栈都看不到。
实操建议:
- 所有
crontab条目末尾必须显式重定向输出:*/5 * * * * /usr/bin/php /path/to/your/script.php >> /var/log/tp6-cron.log 2>&1 - 在脚本开头强制开启错误报告:
error_reporting(E_ALL); ini_set('display_errors', 0); ini_set('log_errors', 1); - TP6.0 中避免依赖
$_SERVER['argv']或getopt()——crontab环境下这些变量可能为空或格式异常,改用input()->param()或明确传参方式
TP6.0 如何捕获 SIGTERM 实现优雅退出?
Linux 服务重启、容器停止、甚至某些云平台缩容时,会向进程发送 SIGTERM。TP6 默认不处理该信号,导致数据库连接未关闭、事务未回滚、临时文件未清理,下次启动就可能卡在锁表或文件占用上。
实操建议:
- 在入口脚本(如
think命令封装脚本或自定义命令类中)注册信号处理器:pcntl_signal(SIGTERM, [$this, 'handleExit']); -
handleExit()方法里务必调用Db::close()、Cache::clear()、unlink($tempFile)等清理动作,最后用exit(0) - 注意:PHP 的
pcntl扩展在 CLI 模式下才可用,且不能在 Web SAPI(如 Apache)中使用 ——crontab调用的是 CLI,没问题
为什么 crontab 重启 TP6 服务后,端口仍被占用?
常见现象是:定时任务执行 php think start 启动 HTTP 服务,但旧进程没真正退出,新进程 bind 失败,netstat -tuln | grep :8080 显示 PID 未变。这不是 TP6 Bug,而是信号传递和进程树管理问题。
实操建议:
- 不要直接
php think start—— 它启动的是守护进程,crontab无法控制其子进程生命周期;改用php think serve --port=8080 --no-debug(前台模式),再配合killall -q php清理 - 更稳妥做法:用
ps -ef | grep 'think serve' | grep -v grep | awk '{print $2}' | xargs kill -TERM先发SIGTERM,等 3 秒后kill -KILL强杀残留 - TP6.0 的
think:serv命令不支持--pidfile,需自己在启动脚本中写入 PID 到文件,并读取后精准 kill
crontab + TP6 自动重启脚本总失败?检查这三点
很多脚本看着逻辑正确,却反复失败,核心问题往往出在环境隔离和权限链路上,而不是代码本身。
实操建议:
- 所有路径必须用绝对路径:
/usr/bin/php不是php,/var/www/app/think不是think - 确保
crontab -u www-data -e(或对应运行用户)而非root—— TP6 应用目录权限通常不允许 root 写日志或缓存 - 关键一步:在脚本开头
source /etc/environment或. /etc/profile,否则PATH、HOME、LANG全部丢失,Composer autoloader 加载失败、MySQL socket 找不到、中文日志乱码
TP6.0 在 crontab 环境下的稳定性,不取决于框架多强大,而在于你是否主动接管了信号、路径、环境变量这三个最底层的环节。漏掉任何一个,都可能让“自动重启”变成“自动失效”。


















