简体   繁体   中英

How to fix error “Only one ConfirmCallback is supported by each RabbitTemplate” on subsequent requests

I am new to RabbitMQ and currently working on RabbitMQ publish confirms acknowledgments in my web application. On every new request, sending message to RabbitMQ server to process it asynchronously and also enabled confirms to get acknowledgments from the RMQ server.

When trying in local, on the first request it is fine but on subsequent requests, getting following error "Only one ConfirmCallback is supported by each RabbitTemplate".

After some research, if I add a check (template.isConfirmListener()) before setting confirm callback, not getting error. But how can we override Confirm Callbacks for different requests if required? Is this expected behaviour or am I am doing anything wrong here?

Environment:

  1. Spring Boot version 2.1.7.RELEASE
  2. Java 8

Please find the code as below.

Controller file

package com.example.apis;

import java.util.UUID;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;



@Controller
public class ProducerController {

    @Autowired
    private RabbitTemplate template;

    private String exchange = "test";
    private String routingKey = "test";

    @GetMapping("/send")
    @ResponseBody
    public String sendRequestToRMQ() {


        template.convertAndSend(exchange, routingKey, "Test Message", getCorrelationData());
        template.setMandatory(true);
        template.setConfirmCallback(new ConfirmCallback() {

            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("Confirm Callback!");
                System.out.println(correlationData.getId());
                System.out.println(ack);
            }
        });

        return "Success";
    }

    @GetMapping("/send1")
    @ResponseBody
    public String sendRequestToRMQ2() {


        template.convertAndSend(exchange, routingKey, "Test Message", getCorrelationData());
        template.setMandatory(true);
        template.setConfirmCallback(new ConfirmCallback() {

            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("Confirm Callback!");
                System.out.println(correlationData.getId());
                System.out.println(ack);
            }
        });

        return "Success";
    }

    private CorrelationData getCorrelationData() {
        return new CorrelationData(UUID.randomUUID().toString());
    }
}

Configuration file

package com.example.conf;

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
 public class ConnectionConfig {
     @Value("${spring.rabbitmq.host:localhost}")
     public String host;

     @Value("${spring.rabbitmq.port:5672}")
     public int port;

     @Value("${spring.rabbitmq.username:guest}")
     public String username;

     @Value("${spring.rabbitmq.password:guest}")
     public String password;

     @Value("${spring.rabbitmq.virtual-host:/}")
     public String virtualHost;

     @Bean
     public ConnectionFactory getConnectionFactory(){
         CachingConnectionFactory factory=new CachingConnectionFactory();
         factory.setHost(host);
         factory.setPort(port);
         factory.setUsername(username);
         factory.setPassword(password);
         factory.setVirtualHost(virtualHost);
         factory.setPublisherConfirms(true);
         factory.setPublisherReturns(true);
         return factory;
     }
 }

Please help me. Thanks

No, it is expected behavior: only one ConfirmCallback can be injected into the RabbitTemplate . You need consider to do that only once, somewhere in the @PostConstrcut , but not for every single request. Of course, you might need to revise your logic since now a ConfirmCallback is going to be shared for all the request initiated into RabbitTemplate .

You may consider some smart logic in your common ConfirmCallback to store request in the map based on the getCorrelationData() and restore that entry from the callback method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM