Keeping Spring Boot Camels alive

We had a situation where a camel route running in a non-web Spring Boot application would die occasionally, taking down the application with it.

The route in question served as a bridge between two JMS brokers, one remote, not under our control, and one local to us. It turned out that the remote broker would become unreachable from time to time, usually not for more than a few seconds. A not unexpected or unreasonable state of affairs. When this happened the following appears in the logs:

2017-03-07 13:39:33.792 [Camel (MyContext) thread #0 - JmsConsumer[myTopic]] ERROR o.a.c.c.j.DefaultJmsMessageListenerContainer - Could not refresh JMS Connection for destination 'myTopic' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: Could not connect to broker URL: ssl://broker.somewhere.com:61616. Reason: java.net.ConnectException: Connection refused: connect

The exception looks fine - it's the behaviour of the application that is not. It should retry until the other end comes online again.

It turns out that this behaviour is caused by the way we're starting Camel in our application's main method. We have:

public class OurService {
...
public static void main(String[] args) {
    ApplicationContext applicationContext = SpringApplication.run(OurService.class, args);
}

The problem here is that when the Camel route dies (eg when it there is a connection issue in the "from" end of a route) then this application thread will also die. An attempt is actually made to reconnect to the remote broker, but not in time to save our app.

Camel provides a way of changing this behaviour, which is to use the CamelSpringBootApplicationController class. Add a couple of lines to the main method like so:

ApplicationContext applicationContext = SpringAp plication.run(OurService.class, args);
    CamelSpringBootApplicationController applicationController
            = applicationContext.getBean(CamelSpringBootApplicationController.class);
    applicationController.run();

Now CamelSpringBootApplicationController will effectively hang around until Spring Boot is shutdown. When the remote broker dies the reconnect attempts are made (forever) until successful, and then life can go on as before.

For further hints and tips about using Spring Boot with Camel check out Camel's page on the subject.