Rabbitmq 如何配置";“端到端”;publisher与Spring AMQP确认

Rabbitmq 如何配置";“端到端”;publisher与Spring AMQP确认,rabbitmq,spring-amqp,Rabbitmq,Spring Amqp,我想将publisher-confirms与RabbitMQ和Spring-AMQP一起使用,这样,如果侦听器在处理消息期间抛出异常,那么消息确认回调将获得一个NACK 下面,我讨论的是用红色标记的用例: 主要问题是: 如何配置ConnectionFactory、RabbitTemplate和ListenerContainer以启用手动NACK 如果出现异常,我必须在侦听器中执行什么操作才能调用消息并使用success=false调用确认回调 这是我的豆子: @Bean 公共连接工厂连接工厂(

我想将publisher-confirms与RabbitMQ和Spring-AMQP一起使用,这样,如果侦听器在处理消息期间抛出异常,那么消息确认回调将获得一个NACK

下面,我讨论的是用红色标记的用例:

主要问题是:

  • 如何配置ConnectionFactory、RabbitTemplate和ListenerContainer以启用手动NACK

  • 如果出现异常,我必须在侦听器中执行什么操作才能调用消息并使用
    success=false
    调用确认回调

  • 这是我的豆子:

    @Bean
    公共连接工厂连接工厂(){
    CachingConnectionFactory connectionFactory=新的CachingConnectionFactory(“localhost”);
    connectionFactory.SetPublisherConfigrms(true);
    返回连接工厂;
    }
    @豆子
    公共ConfirmCallback ConfirmCallback(){
    返回新的ConfirmCallbackTestImplementation();
    }
    @豆子
    公共RabbitTemplate RabbitTemplate(ConnectionFactory ConnectionFactory,ConfirmCallback ConfirmCallback){
    RabbitTemplate RabbitTemplate=新的RabbitTemplate(连接工厂);
    setConfirmCallback(confirmCallback);
    rabbitTemplate.setExchange(直接交换);
    返回兔模板;
    }
    @豆子
    公共故障消息侦听器故障侦听器(RabbitAdmin RabbitAdmin、DirectExchange exchange、ConnectionFactory ConnectionFactory){
    队列=队列(rabbitAdmin,exchange,“faultyListener”);
    FaultyMessageListener=新的FaultyMessageListener();
    SimpleMessageListenerContainer容器=新的SimpleMessageListenerContainer(connectionFactory);
    setMessageListener(监听器);
    container.setQueues(队列);
    container.setDefaultRequeueRejected(false);
    container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
    container.start();
    返回侦听器;
    }
    专用队列队列(RabbitAdmin RabbitAdmin、DirectExchange exchange、字符串路由密钥){
    队列=新队列(routingKey,true,false,true);
    rabbitAdmin.declareQueue(队列);
    rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchange).with(routingKey));
    返回队列;
    }
    
    以下是我的侦听器实现:

    public类FaultyMessageListener实现ChannelAwareMessageListener{
    private final List receivedMessages=new ArrayList();
    专用最终倒计时闩锁=新倒计时闩锁(1);
    @凌驾
    public void onMessage(消息消息、通道)引发异常{
    receivedMessages.add(消息);
    channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
    倒计时();
    抛出新的AmqpException(“无法处理消息”);
    }
    }
    
    这是我的确认回电:

    公共静态类ConfirmCallbackTestImplementation实现ConfirmCallback{
    private volatile Map confirmations=new HashMap();
    私有易失性HashMap ExpectationLatchs=新HashMap();
    @凌驾
    public void confirm(CorrelationData CorrelationData,布尔成功,字符串s){
    confirmations.put(correlationData.getId(),success);
    expectationLatchs.get(correlationData.getId()).countDown();
    }
    公共倒计时闩锁预期(字符串相关ID){
    CountDownLatch闩锁=新的CountDownLatch(1);
    this.expectationLatchs.put(correlationId,latch);
    回程闩锁;
    }
    }
    
    然后,我使用以下测试来验证所需的行为:

    @Autowired
    私有rabbit模板;
    @自动连线
    私人过错信息披露人过错信息披露人;
    @自动连线
    私有ConfirmCallbackTestImplementation testConfirmCallback;
    @试验
    public void sendMessageToFaultyMessageListenerResultsInNack()引发InterruptedException{
    字符串correlationId=“corr-data-test-2”;
    CountDownLatch confirmationLatch=testConfirmCallback.expect(correlationId);
    convertAndSend(“ConnectionsTests.PublisherConfig”、“faultyListener”、“FaultMessage”、新的CorrelationData(correlationId));
    assertTrue(faultyListener.latch.await(1,TimeUnit.SECONDS));
    确认锁存。等待(1,时间单位。秒);
    断言(faultyListener.receivedMessages.size(),为(1));
    断言(testConfirmCallback.confirmations.get(correlationId)为(false));
    }
    
    试验结果如下:

    java.lang.AssertionError: 
        Expected: is <false>
             but: was <true>
    
    java.lang.AssertionError:
    预期:是吗
    但是:是吗
    

    最后一句话。对于我来说,这就像总是用
    success=true
    调用confirm回调,而不是使用
    success=false
    我在侦听器中期望的
    channel.basicNack(…)
    调用。

    它不会那样工作;发布服务器端的ack/nack纯粹是代理是否接受了消息。事实上,nack很少返回,因为它意味着代理本身存在问题-请参阅

    只有在负责队列的Erlang进程中发生内部错误时,才会传递basic.nack

    类似地,消费者侧的ack/nack纯粹是关于消费者是否已接受对消息的责任,并且nack允许消息被重新排队、丢弃或路由到死信队列

    消息发布后,消费者将无法与发布者进行通信。如果需要此类通信,则需要设置回复队列

    如果希望发布者和使用者之间紧密耦合,则可以使用。如果使用者抛出异常,它将被传播回发布者-但是,该机制仅支持Java
    Serializable
    对象

    尽管文档引用了XML,但您可以将代理和服务调用程序连接为
    @Bean
    s