codeigniter中rabbitmq消费者需通过cli模式运行,封装为命令、用nohup启动并配合redis控制启停;推荐php-amqplib库;确保队列durable、消息delivery_mode=2、手动ack,并严格校验vhost一致性。

CodeIgniter 里怎么让 RabbitMQ 消费者持续运行不退出
CI 默认是 Web 请求生命周期,一次请求结束就销毁所有资源,所以直接在控制器里写个 while(true) 是行不通的——PHP 进程会超时、被 Apache/Nginx 杀掉,或因内存泄漏崩溃。
必须用 CLI 模式启动独立进程,并配合外部守护机制。常见做法是:
- 把消费者逻辑封装成 CLI 命令(比如
php index.php cli rabbitmq consume) - 用
nohup+&启动,重定向日志,避免终端关闭导致中断 - 加 Redis 标志位(如
redis->set('rabbitmq:consumer:status', 'running'))用于手动启停控制 - 每轮循环末尾加
sleep(1),防止 CPU 疯转;同时检查 Redis 中的停止信号,支持优雅退出
别依赖 set_time_limit(0) ——它只对 Web SAPI 有效,CLI 下默认不限时,但不解决进程被系统回收的问题。
php_amqp 扩展和 php-amqplib 库该选哪个
php_amqp 是 C 扩展,性能高、内存占用低,但 Windows 下编译麻烦,PHP 版本升级后容易报 undefined symbol 错误;php-amqplib 是纯 PHP 实现,通过 Composer 安装(composer require php-amqplib/php-amqplib),跨平台稳定,调试友好,适合 CI 这类轻量级项目。
除非你压测发现消息吞吐卡在 PHP 层(比如单机每秒处理 >5000 条),否则优先用 php-amqplib。它对 AMQP 协议支持完整,能轻松实现 durable 队列、ack 确认、死信交换等关键特性。
注意:CI 的 autoloader 不会自动加载 Composer 类库,需在入口文件 index.php 或基础控制器里显式调用 require FCPATH . 'vendor/autoload.php';。
如何确保 RabbitMQ 消息不丢,尤其在 CI 重启或崩溃时
消息丢失通常发生在三个环节:生产者发出去就不管、RabbitMQ 自身没落盘、消费者拿到就删没确认。CI 作为生产者时,必须做到:
- 声明队列时设
durable => true(对应channel->queue_declare()的durable参数) - 发送消息时设
delivery_mode => 2(即持久化消息),否则重启后消息清空 - 消费者端务必用
channel->basic_consume()并手动调用$channel->basic_ack($delivery_info['delivery_tag'])
CI 控制器里如果用 php-amqplib 发消息,别漏掉 try/catch ——网络断开时 $channel->basic_publish() 会抛出 AMQPConnectionException,不捕获会导致整个请求 500,而消息其实根本没发出去。
为什么 RabbitMQ 管理界面能看到队列,但 CI 消费者收不到消息
最常见原因是 vhost(虚拟主机)不一致。RabbitMQ 默认 vhost 是 /,但很多 CI 配置里连的是空字符串或 %2F(URL 编码后的 /),实际连接到了 amq.default 这类默认 vhost,队列创建在别处。
检查点:
- 连接 URL 是否写成
amqp://guest:guest@localhost:5672/%2F(正确)而非amqp://guest:guest@localhost:5672/(错误,会被解析为 root vhost) - CI 配置中是否显式指定
vhost => '/'(php-amqplib要求必须传,不能省略) - 管理界面右上角切换 vhost,确认你看到的队列确实属于当前连接所用的 vhost
另一个隐蔽坑:CI 的 CLI 进程如果用了 opcache.enable_cli=1,修改消费者代码后可能不生效,得清 opcache 或临时关掉再试。











