How can I stop a route from a route
The CamelContext provides API for managing routes at runtime. It has a stopRoute(id)
and startRoute(id)
methods.
Stopping a route during routing an existing message is a bit tricky. The reason for that is Camel will Graceful Shutdown the route you are stopping. And if you do that while a message is being routed the Graceful Shutdown will try to wait until that message has been processed.
The best practice for stopping a route from a route, is to either:
-
signal to another thread to stop the route
-
spin off a new thread to stop the route
Using another thread to stop the route is also what is normally used when stopping Camel itself, or for example when an application in a server is stopped etc. Its too tricky and hard to stop a route using the same thread that currently is processing a message from the route. This is not advised to do, and can cause unforeseen side effects.
Using a latch to stop Camel from a route
In this example we use a CountdownLatch
to signal when Camel should stop, triggered from a route.
// use a latch as signal when to stop Camel
private final CountDownLatch latch = new CountDownLatch(1);
public void testStopCamelFromRoute() throws Exception {
// create camel, add routes, and start camel
CamelContext context = new DefaultCamelContext();
context.addRoutes(createMyRoutes());
context.start();
// setup mock expectations for unit test
MockEndpoint start = context.getEndpoint("mock:start", MockEndpoint.class);
start.expectedMessageCount(1);
MockEndpoint done = context.getEndpoint("mock:done", MockEndpoint.class);
done.expectedMessageCount(1);
// send a message to the route
ProducerTemplate template = context.createProducerTemplate();
template.sendBody("direct:start", "Hello Camel");
// wait for the latch (use 1 minute as fail safe, due unit test)
assertTrue(latch.await(1, TimeUnit.MINUTES));
// stop camel
context.stop();
// unit test assertions
start.assertIsSatisfied();
done.assertIsSatisfied();
}
And in the route we call the latch as shown:
public RouteBuilder createMyRoutes() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:start").routeId("myRoute")
.to("mock:start")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
// stop Camel by signalling to the latch
latch.countDown();
}
}).to("mock:done");
}
};
}
Using a thread to stop a route from a route
In this example we use a separate Thread
to stop the route, triggered from the route itself.
public void testStopRouteFromRoute() throws Exception {
// create camel, add routes, and start camel
CamelContext context = new DefaultCamelContext();
context.addRoutes(createMyRoutes());
context.start();
assertTrue("Route myRoute should be started", context.getRouteStatus("myRoute").isStarted());
assertTrue("Route bar should be started", context.getRouteStatus("bar").isStarted());
// setup mock expectations for unit test
MockEndpoint start = context.getEndpoint("mock:start", MockEndpoint.class);
start.expectedMessageCount(1);
MockEndpoint done = context.getEndpoint("mock:done", MockEndpoint.class);
done.expectedMessageCount(1);
// send a message to the route
ProducerTemplate template = context.createProducerTemplate();
template.sendBody("direct:start", "Hello Camel");
// just wait a bit for the thread to stop the route
Thread.sleep(1000);
// the route should now be stopped
assertTrue("Route myRoute should be stopped", context.getRouteStatus("myRoute").isStopped());
assertTrue("Route bar should be started", context.getRouteStatus("bar").isStarted());
// stop camel
context.stop();
// unit test assertions
start.assertIsSatisfied();
done.assertIsSatisfied();
}
And in the route we create the thread and call the stopRoute
method as shown:
public RouteBuilder createMyRoutes() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:start").routeId("myRoute")
.to("mock:start")
.process(new Processor() {
Thread stop;
@Override
public void process(final Exchange exchange) throws Exception {
// stop this route using a thread that will stop
// this route gracefully while we are still running
if (stop == null) {
stop = new Thread() {
@Override
public void run() {
try {
exchange.getContext().getRouteController().stopRoute("myRoute");
} catch (Exception e) {
// ignore
}
}
};
}
// start the thread that stops this route
stop.start();
}
}).to("mock:done");
from("direct:bar").routeId("bar")
.to("mock:bar");
}
};
}
Alternative solutions
Camel provides another feature for managing routes at runtime which is RoutePolicy.
And CamelContext also provides API for suspend/resume of routes, and shutdown as well.
-
suspend/resume is faster than stop/start. For example a HTTP server will still run but deny any incoming requests. Whereas if it was stopped the HTTP listener would have been stopped.
-
shutdown means the route is being removed from CamelContext and cannot be started again. Its also removed from JMX. A route must have been stopped prior to be shutdown.
See more details about the Lifecycle.
You can also use the ControlBus component to let it stop/start routes. |