使用队列时,第一步生产者发送消息到队列中,生产者有责任保证消息正确进度队列.
可以通过发布确认
实现.
流程:
- 消息
Message
首先到达交换机Exchange
- 然后由交换机根据路由键
RoutingKey
分配到合适的队列Queue
.
先来看最基础的,只发送,不管消息能否到达队列,可能造成消息丢失
# index.php
channel();
//定义交换机
$channel->exchange_declare('PHP-Direct-Exchange','direct');
//定义队列 - 1
$channel->queue_declare('PHP-Queue',false,true,false,false,false);
//绑定
$channel->queue_bind('PHP-Queue','PHP-Direct-Exchange','key1');
//定义消息并发送
$message = new AMQPMessage('hello world');
$channel->basic_publish($message,'PHP-Direct-Exchange',$routingKey,true);
$channel->close();
$connection->close();
}catch (\Exception $exception){
echo "异常信息".$exception->getMessage();
}
命令行执行脚本
php index.php key1
可能由于未知原因,导致消息丢失,而生产者完全无法感知.
所以开启发布确认
.
- 开启
发布确认
//开启发布确认
$channel->confirm_select();
- 需要几个回调函数.
//成功到达交换机时触发
$channel->set_ack_handler(function(AMQPMessage $msg){
echo '成功到达交换机'.PHP_EOL;
});
//nack,MQ内部错误时触发
$channel->set_nack_handler(function(AMQPMessage $msg){
echo 'nack'.PHP_EOL;
});
//消息到达交换机,但是没有进入合适的队列,消息回退
$channel->set_return_listener(function ($reply_code,$reply_text,$exchange,$routing_key,AMQPMessage $msg){
echo '没有进入合适的队列'.PHP_EOL;
});
- 生产者发布消息时设置
mandatory=true
,表示消息无法路由到队列时,会退回给生产者
$channel->basic_publish($message,'PHP-Direct-Exchange',$routingKey,true);
- 使用
wait_for_pending_acks_returns()
方法等待server回执
$channel->wait_for_pending_acks_returns();
接下来判断消息是否成功入队
需要注意回调的触发顺序:看演示.
使用正确的routingKey
,set_ack_handler()回调触发.
故意使用错误的
routingKey
看下效果.两个回调都触发了
所以:
set_ack_handler()
写成功的逻辑.
set_return_listener()
写失败的逻辑,并且终止脚本执行.否则会导致,先执行一遍失败逻辑,又执行一遍成功逻辑.
完整代码如下:
channel();
//定义交换机
$channel->exchange_declare('PHP-Direct-Exchange','direct');
//定义队列 - 1
$channel->queue_declare('PHP-Queue',false,true,false,false,false);
//绑定
$channel->queue_bind('PHP-Queue','PHP-Direct-Exchange','key1');
//开启发布确认
$channel->confirm_select();
//成功到达交换机时执行
$channel->set_ack_handler(function(AMQPMessage $msg){
echo '入队成功逻辑'.PHP_EOL;
});
//nack,rabbitMQ内部错误时触发
$channel->set_nack_handler(function(AMQPMessage $msg){
echo 'nack'.PHP_EOL;
});
//消息到达交换机,但是没有进入合适的队列,消息回退
$channel->set_return_listener(function (
$reply_code,
$reply_text,
$exchange,
$routing_key,
AMQPMessage $msg
) use (
$channel,
$connection
)
{
echo '消息退回,入队失败逻辑'.PHP_EOL;
$channel->close();
$connection->close();
exit();
});
//定义消息并发送
$message = new AMQPMessage('hello world');
$channel->basic_publish($message,'PHP-Direct-Exchange',$routingKey,true);
//等待server确认
$channel->wait_for_pending_acks_returns();
$channel->close();
$connection->close();
}catch (\Exception $exception){
echo "异常信息".$exception->getMessage();
}