1

HttpConnections where not being used efficiently by our code using Axis2 1.5.1 project. By setting a certain limit of max connections per host and stressing the application, responsiveness was not the good I expected according the intentional limits and sometimes connections got stucked indefinitly, so the available connections were each time less till reaching the point that none request was attended by the application.

Configuration:

MultiThreadedHttpConnectionManager connManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams connectionManagerParams = connManager.getParams();
connectionManagerParams.setMaxTotalConnections(httpMaxConnections);
connectionManagerParams.setDefaultMaxConnectionsPerHost(httpMaxConnectionsPerHost);

HttpClient httpClient = new HttpClient(connManager);

ConfigurationContext axisContext;
try {
    axisContext = ConfigurationContextFactory.createDefaultConfigurationContext();
} catch (Exception e) {
    throw new AxisFault(e.getMessage());
}

axisContext.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);

service = new MyStub(axisContext, url);

ServiceClient serviceClient = service._getServiceClient();

serviceClient.getOptions().setProperty(HTTPConstants.CONNECTION_TIMEOUT, httpConnectionTimeout);
serviceClient.getOptions().setProperty(HTTPConstants.SO_TIMEOUT, httpReadTimeout);
serviceClient.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Constants.VALUE_TRUE);

So, as you can see, we're defining max. connections and timeouts.

I have a workaround I will share, hoping to help somebody under hurries as I was. I'll mark my answer as the good one a few days later if there isn't any better answer from experts.

1 Answers1

3

1) PoolTimeout to prevent the connections that got stucked (for any reason)

Next line helped us to prevent Axis2 to lose connections that got stucked forever:

httpClient.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, 1000L);

Let's call it PoolTimeout in this entry. Make sure it's a Long, since an Integer (or int) would raise a ClassCastException that will prevent your service to even be triggered outside your client.

The system you're developing, and that is using Axis, could be in turn a client for another system. And that other system will have for sure an specific ConnectionTimeout. So I suggest

PoolTimeout <= ConnectionTimeout

Example:

serviceClient.getOptions().setProperty(HTTPConstants.CONNECTION_TIMEOUT, httpConnectionTimeout);
httpClient.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, Long.valueOf(httpConnectionTimeout) );

2) Connections release

I was using Amila's suggestion for connection management, but actually the connections were not released as fast as in advance I expected they would be (because I prepared consciously the delay times mocked external system would respond to fit limits accordingly my tunning configuration).

So I found that next lines, in method org.apache.axis2.client.OperationClient.executeImpl(boolean), helped to mark as available the connection in the pool as soon as it's been used:

HttpMethod method = (HttpMethod) getOperationContext().getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE)
        .getProperty(HTTPConstants.HTTP_METHOD);
method.releaseConnection();

That's what Axis is trying to do when calling serviceClient.cleanupTransport() but it seems the context is not correct.

Now, performance tunning is working in a predictable way, so it's in hands of our integrators to select the tunning configuration that best suits production needs.

A better answer will be highly appreciated.

  • Note: To "override" *OperationClient.executeImpl(boolean)* standard behavior I created a copy of **ServiceClient**, **Options** and **OperationClient** and set them into my stub like these: stub._setServiceClient( serviceClient = new MyServiceClient(stub._getServiceClient()) ); These three classes are just delegating method calls to Axis original classes but overriding executeImpl to release the connection. –  Oct 04 '13 at 17:35