不能。CI4本身不支持Worker模式,需借助RoadRunner或Swoole等外部容器部署,其核心设计基于PSR-7/PSR-15,依赖public/index.php入口,无内置事件循环或协程支持。

CI4 能不能直接用 Worker 模式部署?
不能。CodeIgniter 4 本身不提供 Worker 模式(如 Swoole 的 swoole_http_server 或 RoadRunner 的 rr serve),它默认是传统 PHP-FPM 同步阻塞模型,php spark serve 是单线程开发服务器,仅用于调试——生产环境必须配合外部高性能服务容器,而不是改 CI4 代码去“启用 Worker”。
- CI4 的核心设计基于 PSR-7/PSR-15 和中间件链,所有请求入口仍是
public/index.php,它本身无内置事件循环或协程支持 - 所谓“Worker 模式部署”,实际是指用 Swoole/RoadRunner 替换 PHP-FPM,让 CI4 应用跑在它们提供的 HTTP Server 上,CI4 只负责处理 Request/Response,不感知底层运行时
- 强行修改
index.php去调用Swoole\Http\Server会导致路由、Session、Logger 等模块初始化异常,因为很多服务依赖$_SERVER或 CLI 环境变量,而 Swoole 的生命周期与 FPM 不同
用 RoadRunner 部署 CI4 的最小可行配置
RoadRunner 是目前与 CI4 兼容性最好、文档最清晰的 Worker 容器,它通过 PSR-7 Bridge 加载 CI4 的 public/index.php,无需修改框架源码。
- 先确保项目已用
composer create-project codeigniter4/appstarter myapp初始化,且.env中CI_ENVIRONMENT = production、app.baseURL设为真实域名(如https://api.example.com) - 安装 RoadRunner:下载对应平台二进制(如
rr),放在项目根目录下,权限设为可执行:chmod +x rr - 创建
.rr.yaml,关键字段必须包含:http.address: "0.0.0.0:9000"、server.command: "php public/index.php"、http.pool.supervisor.binary: "php" - 启动:
./rr serve,此时 RoadRunner 会 fork 多个 PHP Worker 进程,每个请求由空闲 Worker 处理,不再每次加载全部 autoloader
注意:server.command 必须指向 public/index.php,不能是 index.php 或其他路径;否则会报 Class 'CodeIgniter\CodeIgniter' not found —— 因为 autoloader 依赖当前工作目录为项目根,而 RoadRunner 默认在 .rr.yaml 所在目录启动。
Swoole 部署 CI4 时最容易崩的三个点
Swoole 虽性能更强,但与 CI4 的兼容需要更精细控制,以下三点不处理,大概率 500 或空白页:
-
$_SERVER变量缺失:Swoole 不自动填充REQUEST_URI、SCRIPT_NAME等,需在public/index.php开头手动补全,例如:$_SERVER['REQUEST_URI'] = $request->server['request_uri'] ?? '/'; - Session 无法复用:CI4 默认用文件驱动,但 Swoole Worker 进程间不共享文件锁,必须切换为
redis或database驱动,并在.env中设session.driver = redis、session.savePath = "tcp://127.0.0.1:6379" - 静态资源被拦截:Swoole 默认把所有请求都交给 PHP 处理,
/css/app.css也会走index.php,需在 Swoole server 配置中显式if (file_exists($filename)) { return $response->end(file_get_contents($filename)); }判断并返回
为什么别在 CI4 里自己写 Worker 启动逻辑
有人尝试在 app/Commands/StartWorker.php 里用 Swoole\HTTP\Server 启动服务,这会导致两个致命问题:
- CI4 的
Services容器是单例且绑定到请求生命周期,Worker 进程复用时,Database、Cache等实例不会自动重置,连接泄漏、缓存污染、事务未提交等问题集中爆发 -
spark命令本质是 CLI 入口,它加载的是app/Config/下的配置,而 Swoole 的onRequest回调里没有 CLI 环境,ENVIRONMENT可能读错,导致日志写错目录、错误报告关闭 - CI4 的
Logger默认写文件,多个 Worker 并发写同一日志文件会损坏内容;必须提前用Monolog替换并配置RotatingFileHandler或SyslogHandler
真正稳定的方案,永远是让 CI4 做好它该做的事:接收 PSR-7 Request,返回 PSR-7 Response;Worker 容器只管调度、网络、进程管理——边界划清了,出问题才好定位。



















