frankenphp中不可用crontab,应使用其内置frankenphp:run-scheduler命令驱动调度,通过config/schedule.php定义任务,确保复用http上下文、中间件及服务容器,避免纯cli调用导致的session丢失、环境变量缺失等问题。

是的,必须换方式。FrankenPHP 是 SAPI 运行时,不是传统 Linux 守护进程环境,crontab 本身在 FrankenPHP 进程内不可用,也不能靠宿主机 crontab 直接调用 PHP 脚本触发 FrankenPHP 的请求生命周期(比如 Session、中间件、路由等会丢失)。
FrankenPHP 里没有 crontab,但有替代机制
FrankenPHP 自带基于 php:8.3-cli(或你指定的 CLI 版本)的内置调度器,通过 frankenphp:run-scheduler 命令驱动,它读取 config/schedule.php(Laravel 风格)或自定义 PHP 调度脚本,本质是定期 fork CLI 子进程执行任务 —— 这才是和 FrankenPHP 生命周期对齐的方式。
- 不能把原
crontab -e里的* * * * * php /path/to/script.php直接照搬;那只是调用 CLI PHP,绕过了 FrankenPHP 的 HTTP 上下文和扩展能力 - FrankenPHP 官方推荐的调度入口是
frankenphp:run-scheduler,它默认每分钟检查一次schedule.php并 dispatch 任务 - 如果你用的是 Symfony 或纯 PHP 项目,需手动实现一个长期运行的调度守护进程(例如用
pcntl_fork()+sleep()),但不推荐 —— 易被 OOM kill 或信号中断
迁移时最常踩的坑:路径、环境变量、用户权限
原 crontab 脚本往往依赖当前用户的 $HOME、$PATH 或 shell profile 加载的环境变量,而 FrankenPHP 的调度子进程默认以 www-data(或容器指定用户)运行,且不加载 shell 环境。
-
$_ENV和getenv()在调度子进程中为空,必须显式在schedule.php中用putenv()或$_SERVER['APP_ENV'] = 'prod'补全关键变量 - 数据库连接、Redis、S3 凭据等敏感配置,不能写死在脚本里,要通过
.env(用vitesse/env或vlucas/phpdotenv加载)并确保该文件对www-data可读 - 文件路径容易出错:原脚本中
__DIR__ . '/../storage/logs'在 CLI 下可能指向错误位置,建议统一用$_SERVER['DOCUMENT_ROOT'] ?? __DIR__或提前定义常量BASE_PATH
如何验证调度是否真正生效
别只看日志有没有输出,要确认三点:是否进入 FrankenPHP 的完整生命周期、是否复用已初始化的服务(如 DB connection pool)、是否受中间件影响(例如 auth 检查)。
- 在调度任务里加一句
file_put_contents('/tmp/scheduler.log', date('c') . " triggered\n", FILE_APPEND);,然后tail -f /tmp/scheduler.log查看时间戳是否准时 - 如果任务需要访问
$_SESSION或request()->ip(),直接报错 —— 这说明你误用了纯 CLI 方式,得改用frankenphp:run-scheduler+ HTTP 触发模拟(例如用curl -s http://localhost:8000/schedule/run?token=xxx) - 注意容器重启后调度不会自动拉起:Docker Compose 中必须把
command: ['frankenphp:run-scheduler']写进独立 service,不能塞进主 FrankenPHP service 的 command 里(会冲突)
调度逻辑越靠近应用层(比如 Laravel 的 schedule:run),越能复用框架能力;越往底层 CLI 走,越容易丢上下文。FrankenPHP 不是“换个 Web 服务器”,它是运行模型的切换 —— 这点最容易被忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











