Search code examples
rabbitmqspring-amqpspring-rabbit

How to handle network time-out exception with rabbit mq while sending messages asynchronously using spring-amqp library


I have written a program which requires multiple queues interaction - means consumer of one queue writes message to another queue and same program has consumer to take action on that queue. Problem: How to handle network time-out issues with queue while sending messages asynchronously using spring rabbit ampq library?or RabbitTemplate.send() function must throw an exception if there are network issues. Currently, I have implemented RabbitTemplate.send() that returns immediately and working fine. But, If network is down, send function returns immediately, doesn't throw any exception and client code assumes success. As a result, i have in-consistent state in DB that message is successfully processed. Please note that call to send function is wrapped inside transactional block and goal is if queue writing fails, DB commit must also rollback. I am exploring following solutions but no success:

  1. Can we configure rabbitTemplate to throw run-time exception if any network connectivity issue so that client call is notified? Please suggest how to do this.

  2. Shall we use synchronous SendAndReceive function call but it leads to delay in processing? Another problem, observed with this function, my consumer code gets notification while sendAndReceive function is still blocked for writing message to queue. Please advise if we can delay notification to queue unless sendAndReceive function is returned. But call to SendAndReceive() was throwing an amqp exception if network was down which we were able to capture, but it has cost associated related to performance. My application is multi-threaded, if multiple threads are sending message using sendAndReceive(), how spring-amqp library manages queue communication? Does it internally creates channel per request? If messages are delivered via same channel, it would impact performance a lot for multi-threaded application.

  3. Can some-one share sample code for using SendAndReceive function with best-practices?

  4. Do we have any function in spring-amqp library to check health of RabbitMQ server before submitting send function call? I explored rabbitTemplate.isRunning() but not getting proper result. If any specific configuration required, please suggest.

  5. Any other solution to consider for guaranteed message delivery or handle network time-out issues to throw runtime exceptions to client..


As per Gary comment below, I have set: rabbitTemplate.setChannelTransacted(true); and it makes call sync. Next part of problem is that if I have transaction block on outer block, call to RabbitTemplate.send() returns immediately. I expect transaction block of outer function must wait for inner function to return, otherwise, ii don't get expected result as my DB changes are persisted though we enabled setChannelTransacted to true. I tried various Transaction propagation level but no success. Please advise if I am doing anything wrong and review transactional propagation settings as below

@Transactional
    public void notifyQueueAndDB(DBRequest dbRequest) {
        logger.info("Updating Request in DB");
        dbService.updateRequest(dbRequest));
        //Below is call to RabbitMQ library 
        mqService.sendmessage(dbRequest); //If sendMessage fails because of network outage, I want DB commit also to be rolled-back.
    } 

MQService defined in another library of project, snippet below.

@Transactional( propagation =  Propagation.NESTED)
 private void sendMessage(......) {
     ....
       rabbitTemplate.send(this.queueExchange, queueName, amqpMessage);

 }catch (Exception exception) {
    throw exception          
}

Solution

    1. Enable transactions so that the send is synchronous.

    or

    1. Use Publisher confirms and wait for the confirmation to be received.

    Either one will be quite a bit slower.