codeigniter 集成 rabbitmq 必须用 php-amqplib、设队列/消息/交换机持久化(durable=true、delivery_mode=2)、消费者手动 basic_ack 并捕获异常,否则易丢消息。

CodeIgniter 默认不带消息队列能力,要让它可靠地发、收 RabbitMQ 消息,核心就三点:用对客户端库、设对持久化参数、补全确认逻辑。漏掉任意一项,CI 一重启或消费者崩一次,消息就丢了。
php-amqplib 是唯一推荐的客户端库
CI 项目里别用过时的 php-amqp 扩展(Windows 下麻烦、Linux 下编译易错),直接 Composer 引入 php-amqplib/php-amqplib。它纯 PHP 实现,跨平台稳定,且支持 AMQP 0-9-1 全特性。
安装命令:composer require php-amqplib/php-amqplib
常见错误现象:Class 'PhpAmqpLib\Connection\AMQPStreamConnection' not found —— 说明没执行 composer autoload 或 CI 的 autoloader 没加载 vendor 目录。确保 application/config/config.php 中 $config['composer_autoload'] = TRUE; 已启用,或在控制器顶部手动 require_once FCPATH . 'vendor/autoload.php';
声明队列和发送消息必须设 durable 和 delivery_mode=2
否则 RabbitMQ 重启后,队列消失、消息清空。这是 CI 场景下丢消息最常踩的坑。
-
$channel->queue_declare($queueName, false, true, false, false)—— 第三个参数true表示durable => true -
$msg = new AMQPMessage($body, ['delivery_mode' => 2])——delivery_mode => 2才是持久化消息,1是内存存储,重启即失 - 交换机也要声明为持久化:
$channel->exchange_declare($exchangeName, 'direct', false, true, false),第三个参数true同样关键
消费者端必须手动 basic_ack,且不能放在 try/catch 外层吞异常
CI 控制器里写消费者脚本时,很多人把 $channel->basic_consume() 放进循环,但忘记在处理完逻辑后调用 $channel->basic_ack($delivery_info['delivery_tag'])。结果消息被取走就删,失败也不重试。
正确结构要点:
- 用
while ($channel->is_consuming()) { $channel->wait(); }驱动消费循环 - 回调函数内,业务逻辑包裹在
try里,成功后才$channel->basic_ack() -
catch块里不要exit或静默忽略,应记录日志,并考虑是否$channel->basic_nack()让消息重回队列 - 避免在控制器里直接跑长时消费进程——CI 生命周期短,更适合用独立 PHP 脚本(如
php cli_consume.php)跑 consumer
CI 控制器发消息时务必包 try/catch
$channel->basic_publish() 在网络中断、RabbitMQ 不可用时会抛出 AMQPConnectionException 或 AMQPChannelException。不捕获,整个 HTTP 请求直接 500,而消息根本没发出去,用户还误以为“已提交”。
实操建议:
- 发消息前检查连接:
if (!$connection->isConnected()) { throw new Exception('RabbitMQ connection lost'); } - 必须用
try { $channel->basic_publish(...); } catch (AMQPConnectionException $e) { log_message('error', 'RabbitMQ publish failed: ' . $e->getMessage()); } - 业务关键消息(如支付成功通知)建议加本地 DB 记录 + 定时补偿任务,不能只信 MQ 一次发送
真正难的不是连上 RabbitMQ,而是让每条消息在 CI 的请求生命周期、服务重启、网络抖动中都可追溯、可重试、不静默失败。参数设对只是起点,异常路径覆盖才是上线前必须验证的环节。











