I have a Camel application that communicates with a remote server over TCP using the netty component. The server has a tendency to hang and so I want to be able to add a configurable timeout on a request so that if a response isn’t returned in X amount of time, I’d get an exception.
The mina component has this capability in the timeout parameter, but the netty component doesn’t appear to have a corresponding option.
I tried accomplishing this with a ReadTimeoutHandler and that came close… but not quite. It starts with creating a HashedWheelTimer when initializing the CamelContext:
HashedWheelTimer timer = new HashedWheelTimer();
JndiRegistry jndi = new JndiRegistry();
jndi.bind("MyClientPipelineFactory", new MyClientPipelineFactory(timer));
And then add it to my pipeline:
public class MyClientPipelineFactory extends ClientPipelineFactory
{
private final Timer timer;
public MyClientPipelineFactory(Timer timer) {
this.timer = timer;
}
public ChannelPipeline getPipeline(NettyProducer producer) throws Exception
{
ChannelPipeline p = pipeline();
p.addLast("timeout", new ReadTimeoutHandler(timer, 30));
// more stuff
return p;
}
}
Finally, I catch any exceptions in my routes configuration:
onException(ReadTimeoutException.class)
.handled(true)
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
Exception exception = (Exception) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
throw new ApplicationException("Connection timed out", exception);
}
});
This almost works. Unfortunately, it is channel specific and not request specific. So as long as I’m communicating with the server, I’m fine. But 30 seconds after I am done, I get a ReadTimeoutException thrown. The problem is that it’s looking for any activity on the wire and not the request/response pairs that I care about.
Am I missing something here? Is there an inherent way of doing request timeouts using Camel+Netty or is there some way to make the ReadTimeoutException work?
(Camel 2.9.2/Netty 3.3.1)
I’m not familiar with Camel but a quick look at the Mina and Netty components suggests that the required functionality is a feature of the Mina component, not Mina, and it’s missing from the Netty component. In camel trunk, the Mina producer has a code path for when sync is true, whereas the Netty producer doesn’t appear to have similar functionality. It might be worth taking the question to the camel mailing lists.
A possible workaround is to create a custom Netty handler that is request / response aware, so you have a handler in your pipeline that starts a timer when the request is sent, and cancels the timer when the response is received.