SpringAMQP errorHandler and returnExceptions problem

Viewed 3439

i am not sure my understanding to errorHandler and returnExceptions is right or not.

but here is my goal: i sent a message from App_A, use @RabbitListener to receive message in App_B.

according to the doc https://docs.spring.io/spring-amqp/docs/2.1.3.BUILD-SNAPSHOT/reference/html/_reference.html#annotation-error-handling

i assume if APP_B has a business exception during process the message,through set errorHandler and returnExceptions in a right way on @RabbitListener can let the exception back to App_A.

do I understood correctly?

if i am rigth, how to use it in a right way?

with my code, i get nothing in APP_A .

here is my code in APP_B

errorHandler:

@Component(value = "errorHandler")
public class ErrorHandler implements RabbitListenerErrorHandler {

    @Override
    public Object handleError(Message arg0, org.springframework.messaging.Message<?> arg1,
            ListenerExecutionFailedException arg2) throws ListenerExecutionFailedException {
        throw new ListenerExecutionFailedException("msg", arg2, null);
    }

}

RabbitListener:

@RabbitListener(
        bindings = @QueueBinding(
            value = @Queue(value = "MRO.updateBaseInfo.queue", durable = "true"),
            exchange = @Exchange(name = "MRO_Exchange", type = ExchangeTypes.DIRECT, durable = "true"),
            key = "baseInfoUpdate"
        ),
//      errorHandler = "errorHandler",
        returnExceptions = "true"
    )
    public void receiveLocationChangeMessage(String message){
        BaseUpdateMessage newBaseInfo = JSON.parseObject(message, BaseUpdateMessage.class);
        dao.upDateBaseInfo(newBaseInfo);
    }

and code in APP_A

@Component
public class MessageSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void editBaseInfo(BaseUpdateMessage message)throws Exception {
        //and i am not sure set RemoteInvocationAwareMessageConverterAdapter in this way is right 
        rabbitTemplate.setMessageConverter(new RemoteInvocationAwareMessageConverterAdapter());

        rabbitTemplate.convertAndSend("MRO_Exchange", "baseInfoUpdate", JSON.toJSONString(message));
    }

}

i am very confuse with three points:

1)do i have to use errorHandler and returnExceptions at the same time? i thought errorHandler is something like a postprocessor that let me custom exception.if i don't need a custom exception can i just set returnExceptions with out errorHandler ?

2)should the method annotated with @RabbitListener return something or void is just fine?

3)in the sender side(my situation is APP_A), does have any specific config to catch the exception?

my workspace environment:

Spring boot 2.1.0

rabbitMQ server 3.7.8 on docker

1 Answers

1) No, you don't need en error handler, unless you want to enhance the exception.

2) If the method returns void; the sender will end up waiting for timeout for a reply that will never arrive, just in case an exception might be thrown; that is probably not a good use of resources. It's better to always send a reply, to free up the publisher side.

3) Just the RemoteInvocationAwareMessageConverterAdapter.

Here's an example:

@SpringBootApplication
public class So53846303Application {

    public static void main(String[] args) {
        SpringApplication.run(So53846303Application.class, args);
    }

    @RabbitListener(queues = "foo", returnExceptions = "true")
    public String listen(String in) {
        throw new RuntimeException("foo");
    }

    @Bean
    public ApplicationRunner runner(RabbitTemplate template) {
        template.setMessageConverter(new RemoteInvocationAwareMessageConverterAdapter());
        return args -> {
            try {
                template.convertSendAndReceive("foo", "bar");
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        };
    }

}

and

org.springframework.amqp.AmqpRemoteException: java.lang.RuntimeException: foo
    at org.springframework.amqp.support.converter.RemoteInvocationAwareMessageConverterAdapter.fromMessage(RemoteInvocationAwareMessageConverterAdapter.java:74)
    at org.springframework.amqp.rabbit.core.RabbitTemplate.convertSendAndReceive(RabbitTemplate.java:1500)
    at org.springframework.amqp.rabbit.core.RabbitTemplate.convertSendAndReceive(RabbitTemplate.java:1433)
    at org.springframework.amqp.rabbit.core.RabbitTemplate.convertSendAndReceive(RabbitTemplate.java:1425)
    at com.example.So53846303Application.lambda$0(So53846303Application.java:28)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:804)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:794)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:324)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
    at com.example.So53846303Application.main(So53846303Application.java:15)
Caused by: java.lang.RuntimeException: foo
    at com.example.So53846303Application.listen(So53846303Application.java:20)

As you can see, there is a local org.springframework.amqp.AmqpRemoteException with the cause being the actual exception thrown on the remote server.

Related