Tuesday, September 16, 2008

Apache CXF and timeouts

We are using Apache CXF inside ServiceMix for webservices. Yesterday I ran into a issue that the client returned from a webservice operation while the operation still ran in ServiceMix. Strange thing I thought and tried to find the cause.

My first approach was to have a look at my webservice SU's and see if I use some timeout values in there for the sending. I didn't find something like this, so I switched to DEBUG log level and gave it another try.

Testing gave me some important facts. The timeout always occured after about 60 seconds, so this seems to be some predefined value and at the time when the client returns there was absolute nothing going on inside the bus, so the cause shouldn't be the ServiceMix itself.

The client seems to be the cause of that behaviour. After doing some searching at Google I found other people ran into this problem as well (as expected). This behaviour is the result of a preset 60 seconds timeout inside the http transport of the client (at least I understood it like this). I saw several suggestions how to solve this but I wasn't able to get it running.

So I gave the cxf irc channel a try and found someone who helped me out with that. Dan Kulp pointed me to the right solution.

It's just about to add a HTTPConduit object with a HTTPClientPolicy. Inside that policy you can configure for example the time out behaviour.

Here is my example code:

MyWebService service = new MyWebService();
MyWebServicePortType client = service.MyWebServicePort();

Client cl = ClientProxy.getClient(client);

HTTPConduit http = (HTTPConduit) cl.getConduit();

HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);

http.setClient(httpClientPolicy);

client.doSomething(...);

Setting the connection timeout and the receive timeout to zero means to wait infinitely having no timeout at all.

So finally I got the problem solved and again many thanks to Dan for helping me out that fast.

8 comments:

Andrew Clegg said...

Just for the record, this is currently not working with Dispatch-based clients (e.g. roll-your-own-XML style).

One workaround, if you have control over the WSDL at the other end, is to add:

<http-conf:client ReceiveTimeout="0"/>

as a child of the wsdl:port element. You'll also need to add:

xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"

to the wsdl:definitions. http-conf is a special directive understood by CXF, which other stacks should ignore.

There's some other workarounds if you don't control the WSDL, see here.

Andrew.

james atherton said...

Thank-you this was very helpful.

Setting the time out to 0 (no timeout) can lead to horrible problems: set it to 500000 milliseconds, or some other number that is larger that you need for normal operations. It just ensures that you don't have thousands of these all waiting forever which finally bring down the system.

Anonymous said...

Thanks, Andrew! Works like a charm!

Alex said...

Thanks a lot for the very useful post!

For people who are using ClientProxyFactoryBean here is a way to get hold of the HTTPConduit :

ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
....
MyService client = (MyService)factory.create();

Client cl = ClientProxy.getClient(client);
HTTPConduit httpConduit = (HTTPConduit) cl.getConduit();

Anonymous said...

Hi,
That's a limited way of thinking. Using Httpconduit is for Java and CXF only.
Web services are supposed to be cross platerform links. So if you use Dot.net or Axis as a client, you post is too limited.
And this should have a server side solution to change the timeout, and not to let the client do it himself.
Rgds.

Anonymous said...

what is difference between ConnectionTimeout and ReceiveTimeout?

Gaurav said...

ConnectionTimeout:

Specifies the amount of time, in milliseconds, that the client will attempt to establish a connection before it times out. The default is 30000 (30 seconds).
0 specifies that the client will continue to attempt to open a connection indefinitely.

ReceiveTimeout:
Specifies the amount of time, in milliseconds, that the client will wait for a response before it times out. The default is 60000.
0 specifies that the client will wait indefinitely.

salouni khele said...

Hey Gaurav
From where did you find out that default timeout is set to 30000ms? Because in most of the articles I read that d default is 60000ms.