The exception handling and retry mechanisms in Apache Camel are quite extensive. In this blogpost we are going to take a look at customizing the retry based on a predicate implementation of our own thereby enabling really fine grained retry logic.
In our example we are going to look at the MEP of the exchange, whenever it is inOnly we are going to retry since no synchronous subscriber is waiting for the response. Conversely, when the MEP of the exchange is inOut we are not going to retry and immediately send back an error. Think fail fast en stuff.
Like mentioned above we can enable this by implementing the Predicate interface from Apache Camel.
The entire class looks like this:
package nl.schiphol.api.integration.redelivery;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Predicate;
import org.apache.camel.component.properties.PropertiesComponent;
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class InvokeEndpointsRedeliveryPolicy implements Predicate{
@Inject
PropertiesComponent properties;
private Integer MAX_REDELIVERIES;
/**
* Returns a Boolean whether or not a redelivery must be executed.
* Whether or not retries should be executed are dependend on two criteria: the MEP of the exchange and the max retries
* If the MEP is inOnly a response is not required immediately and retries can commense up until the max retries
* @implements org.apache.camel.Predicate
* @param exchange The Camel Exchange is used as a parameter, this is dictated by the Predicate interface
* @return Boolean if a redelivery should be executed.
*/
@Override
public boolean matches(Exchange exchange) {
setMaxRedeliveries();
//no redelivery is the default
Boolean shouldRedeliver = false;
ExchangePattern exchangePattern = exchange.getPattern();
Boolean isInOut = exchangePattern.isOutCapable();
Integer redeliveryCounter = getRedeliveryCounter(exchange.getIn().getHeader(Exchange.REDELIVERY_COUNTER, Integer.class));
if(!isInOut && redeliveryCounter < MAX_REDELIVERIES){
shouldRedeliver = true;
}
return shouldRedeliver;
}
private void setMaxRedeliveries() {
try {
String retryAmountProperty = properties.parseUri("{{health-api.invokeEndpoints.retryAmount}}");
MAX_REDELIVERIES = new Integer(retryAmountProperty);
} catch (Exception e) {
MAX_REDELIVERIES = 3;
}
}
private Integer getRedeliveryCounter(Integer redeliveryCounterHeader){
Integer redeliveryCounter = redeliveryCounterHeader;
if(redeliveryCounter == null){
redeliveryCounter = 0;
}
return redeliveryCounter;
}
private Boolean getRetryProperty(Boolean retryProperty) {
Boolean retry = retryProperty;
if(retry == null){
retry = false;
}
return retry;
}
}
In order to use our predicate in our Camel Route for determining the retry use the ‘retryWhile’ statement:
@Override
private void configure() {
from("direct:start").routeId("my-dynamic-retry-route")
.onException(Exception.class).redeliveryDelay(1500).retryWhile(redeliveryPolicy).continued(true).end()
...