codeigniter 4.6.0 不内置消息队列,service('queue') 报错因默认未注册 queue 服务;需手动集成第三方库并在 services.php 显式注册,且 job 必须通过 cli(如 php spark queue:work --daemon)异步执行,脱离 http 生命周期。

CodeIgniter 4.6.0 自身不内置消息队列(MQ)或异步任务调度能力,所有队列相关功能必须通过扩展实现。直接调用 queue:work 或期望框架自动处理后台任务,会失败——因为核心服务容器里根本没有 queue 这个服务。
为什么 service('queue') 报错 “No service for type queue”?
这不是配置漏了,而是根本没注册。CI4.6.0 的 app/Config/Services.php 默认不声明任何队列服务,service() 查不到就抛异常。
- 官方文档明确说明:队列属于“可选扩展”,需手动集成第三方库(如
enqueue/enqueue、php-amqplib/php-amqplib或 Laravel-style 的codeigniter4/queue包) - 即使装了
codeigniter4/queue,它也不会自动注册服务;你得在app/Config/Services.php里显式添加工厂方法 - PHP-FPM 请求生命周期限制:默认 Web 请求超时 30 秒,试图在控制器里
sleep(60)或执行耗时任务,必然中断,不是队列没跑,是根本没机会跑
如何让 job 被真正异步执行?
关键不在“加队列”,而在“脱离 HTTP 生命周期”。CI4.6.0 的 php spark queue:work 命令只是个外壳,背后依赖的是你选的驱动和进程管理方式。
- 必须用 CLI 启动工作进程:
php spark queue:work --daemon(注意--daemon是必需参数,否则只跑一次就退出) - 不能靠 Web 请求触发 job 执行;只能触发“推入队列”,例如:
$this->queue->push(new SendEmailJob(['to' => 'user@example.com'])); - Linux 下需配合
supervisord或systemd管理常驻进程,否则终端关闭后 worker 立即终止 - Redis 驱动比 database 驱动快一个数量级,但要求 Redis 服务可用且配置正确;若
redis://127.0.0.1:6379连不上,worker 日志只会显示 “Connection refused”,不会报具体哪个类出错
job 类里 $db 或 $session 为什么是 null?
异步 job 运行在独立 CLI 进程中,不共享 Web 请求上下文。CI4 的 Database、Session、Request 等服务默认绑定到当前请求生命周期,CLI 下未初始化。
- 不要在 job 构造函数里依赖
Database实例;改用db_connect()手动连接,或在handle()方法内调用service('database') -
session()在 CLI 中不可用,会报 “Session unavailable in CLI mode”;需要持久化状态时,改用数据库或缓存(如cache()->save()) - 日志写入路径要注意:CLI 进程的
WRITEPATH可能和 Web 不同,log_message('error', '...')写到的文件位置可能找不到
本地开发时怎么验证 job 真的进了队列?
别只看命令行输出“Job pushed”,要查底层存储。
- 用 Redis CLI:
redis-cli keys "ci4:queues:*"看队列 key 是否存在;再用lrange ci4:queues:default 0 -1查未消费消息 - 用 database 驱动时,查
jobs表,确认attempts和reserved_at字段变化 - Spark 命令加
-v参数:php spark queue:work -v显示每条 job 的反序列化过程和 handle() 调用栈,比静默模式更容易定位 unserialize 失败问题
.env 里的 REDIS_HOST,而 CLI 进程可能读的是系统环境变量或未加载 .env —— 导致 Web 能推、CLI 拉不到,排查时容易误判为队列逻辑错误。











