php RabbitMQ生产者发布确认

使用队列时,第一步生产者发送消息到队列中,生产者有责任保证消息正确进度队列.
可以通过发布确认实现.
流程:

  1. 消息Message首先到达交换机Exchange
  2. 然后由交换机根据路由键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

可能由于未知原因,导致消息丢失,而生产者完全无法感知.
所以开启发布确认.

  1. 开启发布确认
    //开启发布确认
    $channel->confirm_select();
  1. 需要几个回调函数.
    //成功到达交换机时触发
    $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;
    });
  1. 生产者发布消息时设置mandatory=true,表示消息无法路由到队列时,会退回给生产者
    $channel->basic_publish($message,'PHP-Direct-Exchange',$routingKey,true);
  1. 使用wait_for_pending_acks_returns()方法等待server回执
    $channel->wait_for_pending_acks_returns();

接下来判断消息是否成功入队

需要注意回调的触发顺序:看演示.
使用正确的routingKey,set_ack_handler()回调触发.

image.png

故意使用错误的routingKey看下效果.两个回调都触发了
image.png

所以:
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();
}

你可能感兴趣的:(php RabbitMQ生产者发布确认)