Java Microservice SDK Connection Pool Config

Hi community,

I’m using the Java Microservice SDK (version 2025.34.0) and recognized that under load I get the following exception from the SDK:

jakarta.ws.rs.ProcessingException: org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
	at org.glassfish.jersey.apache.connector.ApacheConnector.apply(ApacheConnector.java:534)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:300)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:674)
	at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:709)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:703)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:391)
	at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:703)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:673)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:413)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:313)
	at com.cumulocity.sdk.client.RestConnector.getClientResponse(RestConnector.java:144)
	at com.cumulocity.sdk.client.RestConnector.get(RestConnector.java:117)
	at com.cumulocity.sdk.client.identity.IdentityApiImpl.getExternalId(IdentityApiImpl.java:72)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
	at jdk.proxy2/jdk.proxy2.$Proxy135.getExternalId(Unknown Source)
	at dynamic.mapping.core.facade.IdentityFacade.resolveExternalId2GlobalId(IdentityFacade.java:63)
	at dynamic.mapping.core.C8YAgent.lambda$resolveExternalId2GlobalId$0(C8YAgent.java:187)
	at com.cumulocity.microservice.context.ContextServiceImpl.callWithinContext(ContextServiceImpl.java:78)
	at com.cumulocity.microservice.subscription.service.impl.MicroserviceSubscriptionsServiceImpl.lambda$callForTenant$8(MicroserviceSubscriptionsServiceImpl.java:251)
	at java.base/java.util.Optional.map(Optional.java:260)
	at com.cumulocity.microservice.subscription.service.impl.MicroserviceSubscriptionsServiceImpl.callForTenant(MicroserviceSubscriptionsServiceImpl.java:251)
	at dynamic.mapping.core.C8YAgent.resolveExternalId2GlobalId(C8YAgent.java:180)
	at dynamic.mapping.processor.inbound.BaseProcessorInbound.prepareAndSubstituteInPayload(BaseProcessorInbound.java:299)
	at dynamic.mapping.processor.inbound.BaseProcessorInbound.getBuildProcessingContext(BaseProcessorInbound.java:232)
	at dynamic.mapping.processor.inbound.BaseProcessorInbound.substituteInTargetAndSend(BaseProcessorInbound.java:168)
	at dynamic.mapping.processor.inbound.DispatcherInbound$MappingInboundTask.processMessage(DispatcherInbound.java:431)
	at dynamic.mapping.processor.inbound.DispatcherInbound$MappingInboundTask.call(DispatcherInbound.java:216)
	at dynamic.mapping.processor.inbound.DispatcherInbound$MappingInboundTask.call(DispatcherInbound.java:104)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.lang.VirtualThread.run(VirtualThread.java:329)
Caused by: org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:316)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:282)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
	at org.glassfish.jersey.apache.connector.ApacheConnector.apply(ApacheConnector.java:486)
	... 40 common frames omitted

Two questions to that exception:

  1. What is the current connection pool configuration (max connections & timeout) used at Microservice SDK?
  2. I don’t think it’s a connection leek more likely a side effect of too many threads requesting a connection at the same time. Do you have any suggestion how to avoid that?

Here are the Connection Pool default settings of the Microservice SDK:

https://github.com/Cumulocity-IoT/cumulocity-clients-java-internal/blob/develop/java-client/src/main/java/com/cumulocity/sdk/client/HttpClientConfig.java
https://github.com/Cumulocity-IoT/cumulocity-clients-java-internal/blob/develop/java-client/src/main/java/com/cumulocity/sdk/client/ConnectionPoolConfig.java

@Default
private boolean enabled = true;
@Default
private int perHost = 50;
@Default
private int max = 100;
@Default
private int awaitTimeout = 10000;

You can change them by adding the following properties to your application.yaml:

C8Y.httpClient.pool.enabled=true
C8Y.httpClient.pool.perHost=100
C8Y.httpClient.pool.max=150
1 Like