M. Justin M. Justin - 3 months ago 22
Java Question

How can I cleanly shut down a RabbitTemplate in Spring Rabbit?

I've written a script which uses Spring Rabbit to put a number of messages on a Rabbit queue using RabbitTemplate.convertAndSend, and then exits. However, the Rabbit connection appears to keep the app alive even after the message has been enqueued. I have not found a way to cleanly tell the Rabbit server to stop after the messages have been enqueued.

The best solution I've been able to come up with is to change my convertAndSend calls to convertSendAndReceive so that I know the message has been successfully enqueued, and then exit using System.exit(0). I switched to convertSendAndReceive as it appears that convertAndSend happens in a background thread or somesuch, since if I do a System.exit(0) after doing a number of those calls, only the first so many of them will succeed.

Note that merely creating a RabbitTemplate does not cause this behavior; using it via one of the "send" methods does.

The following code illustrates the issue.

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import static issues.RabbitSettings.*; //Static fields containing my test Rabbit connection info

public class RabbitTemplateShutdownIssue {
public static void main(String[] args) {
RabbitTemplate rabbitTemplate = createRabbitTemplate();
rabbitTemplate.convertAndSend(ROUTING_KEY, "Test"); // Or convertSendAndReceive
// The app never exits
}

private static RabbitTemplate createRabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(getConnectionFactory());
rabbitTemplate.setExchange(EXCHANGE);
rabbitTemplate.setMandatory(true);
return rabbitTemplate;
}

private static ConnectionFactory getConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(HOSTNAME);
connectionFactory.setPublisherConfirms(true);
connectionFactory.setVirtualHost(VIRTUAL_HOST);
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
return connectionFactory;
}
}


Is there a way to tell the Rabbit client to shut down, ideally after all messages have been enqueued?

Answer

If you let Spring manage the beans, you can close() the application context when you are finished.

The way you have it configured now (no Spring context), you can call destroy() on the connection factory and everything will shut down.

Using static methods for stuff like this is an anti-pattern; you'll need to store the factory in a static field so you can destroy the one the template is using.

You need a confirm callback to get confirmation that rabbit received the sends.