Controlling route startup and shutdown
When integration logic is composed of routes depending on other routes via direct:
, it is important that they start up in such a way that dependencies are available before exchanges start flowing. If not, you are likely to see this sort of exception being thrown:
org.apache.camel.CamelExchangeException: No consumers available on endpoint: Endpoint[direct://someMissingEndpoint]
Conversely, on application shutdown, messages should complete processing gracefully rather than fail because a dependent route is no longer available. Camel provides a mechanism to define an order for startup and shutdown that addresses both of these issues at the same time.
This recipe will show you how to control the startup and shutdown order of your routes.
Getting ready
Define your desired routing logic as described in either the Using Camel in a Java application recipe, or the Embedding Camel in a Spring application recipe.
The Java code for this recipe is located in the org.camelcookbook.structuringroutes.routecontrol
package.
How to do it...
Set the startupOrder
property associated with the route.
In the XML DSL, add a startupOrder
attribute to the route
element:
<route startupOrder="20"> <from uri="jms:queue:orders"/> <to uri="direct:processOrder"/> </route> <route startupOrder="10"> <from uri="direct:processOrder"/> <process ref="orderProcessor"/> </route>
In the Java DSL, call the startupOrder(..)
method after the from
statement:
from("jms:queue:orders").startupOrder(20) .to("direct:processOrder"); from("direct:processOrder").startupOrder(10) .process(new OrderProcessor());
How it works...
Routes are started in ascending startupOrder
. In the preceding examples, the direct:
route will be started before the main entry point to the integration, which consumes from JMS.
You can assign any integer greater than 0
and less than 1,000
to the startupOrder
. You cannot assign the same value more than once in a Camel context, otherwise it will refuse to start up. Camel will automatically assign values greater than 1,000 to any routes that do not specifically have one defined.
Tip
Drawing inspiration from BASIC programming (for those old enough to remember it), it is useful to assign startupOrder
values in increments of 10. As your integration grows and you find yourself breaking routes down for reuse, it pays to have numbers available so that you do not have to renumber every route.
When you shut down the application, Camel will turn off the routes in the reverse order to that in which it started them. Routes are turned off in descending order.
When a route shuts down, the endpoint consumer is first turned off, and any messages that are flowing through the route ("in-flight") are allowed to complete before the route itself is shut down. Any messages that remain in-flight will be discarded after a timeout of 300 seconds. The timeout is configurable on the Camel context's associated ShutdownStrategy
.
There's more...
Routes can be started and shut down programmatically through the CamelContext startRoute()
and stopRoute()
methods. Since the context is accessible through an Exchange
it is possible to perform custom route control logic. Take, as an example, the following class that stops a route whose name is specified by the body of the exchange:
public class RouteStoppingProcessor implements Processor { @Override public void process(Exchange exchange) throws Exception { final String routeName = exchange.getIn().getBody(String.class); final CamelContext context = exchange.getContext(); new Thread(new Runnable() { @Override public void run() { try { context.stopRoute(routeName); } catch (Exception e) { throw new RuntimeException(e); } } }).start(); } }
Note
It is best practice to manually shut down routes in Camel in a separate thread than in the one that is processing the exchange. The reason behind this is that Camel waits for all exchanges that are flowing through a route to complete before it stops the route. If a thread processing an exchange attempts to shut down the route through which that exchange is flowing, this results in a deadlock.
See the following for more details: http://camel.apache.org/how-can-i-stop-a-route-from-a-route.html.
Routes can also be stopped and started through the use of a Control Bus endpoint:
from("direct:in").id("mainRoute")
.log("Stopping route")
.to("controlbus:route?routeId=mainRoute&action=stop&async=true")
.log("Signalled to stop route")
.to("mock:out");
Tip
Note the use of async=true
to shut down the route in a background thread and thereby prevent a deadlock.
Manual route control does not take into account the startupOrder
, so you must take care when performing it that any routes that you start up or shut down are controlled in an orderly manner.
Routes can be turned off at startup by setting the autoStartup
attribute to false
.
In the XML DSL, add an autoStartup
attribute to the route
element:
<route autoStartup="false">
<from uri="jms:queue:orders"/>
<!-- ... -->
</route>
In the Java DSL, call the autoStartup(..)
method after the from
statement:
from("jms:queue:orders").autoStartup(false)...
You would use this feature if you want to control route availability manually, or through a route policy.
A RoutePolicy
is an interface that you can build upon to determine whether routes should be running or not. Camel provides route policies out of the box for throttling routes (ThrottlingInflightRoutePolicy
), defining uptime through a timer (SimpleScheduledRoutePolicy
), and cron
expressions (CronScheduledRoutePolicy
).
See also
- Configuring route startup ordering and auto startup: http://camel.apache.org/configuring-route-startup-ordering-and-autostartup.html
- Graceful shutdown: http://camel.apache.org/graceful-shutdown.html
- Route Policy: http://camel.apache.org/routepolicy.html
- Camel Control Bus: http://camel.apache.org/controlbus.html