Java SDK connection pooling dropping requests under load

We’re hitting /api/v2/interactions/endpoint from Java, and the default SDK client chokes around two hundred concurrent calls. I’m trying to inject a custom Apache HttpAsyncClient, but Configuration.Builder() won’t accept a setHttpClient override. The docs point to PlatformClient.setHttpClient(), yet that throws a ConcurrentModificationException when multiple threads initialize it. Here’s the pool setup: PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(200); Does the SDK actually support thread-safe pool overrides? The timeout errors keep piling up.

you can’t set the http client on the configuration builder because it’s immutable once built. that’s the first trap. the concurrent modification exception happens because you’re trying to mutate the static PlatformClient singleton while other threads are reading from it or initializing their own instances.

the sdk isn’t designed for high-concurrency stateless workers out of the box if you’re using the global singleton. you need to instantiate a new PureCloudPlatformClientV2 per thread or use a connection pool that handles the locking, but honestly, the cleanest fix in Java is to stop using the global PlatformClient for bulk operations.

create a private instance in your worker class. don’t share it.

import com.nice.icm.platformsdk.api.PureCloudPlatformClientV2;
import com.nice.icm.platformsdk.api.auth.OAuth2ClientCredentials;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class BulkInteractionWorker {

 private final PureCloudPlatformClientV2 client;

 public BulkInteractionWorker(String clientId, String clientSecret) {
 // 1. Setup OAuth
 OAuth2ClientCredentials oAuth = new OAuth2ClientCredentials(clientId, clientSecret);
 
 // 2. Build a pooled connection manager
 PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
 connManager.setMaxTotal(200); // Match your concurrency
 connManager.setDefaultMaxPerRoute(50);

 // 3. Create the http client with the pool
 CloseableHttpClient httpClient = HttpClients.custom()
 .setConnectionManager(connManager)
 .build();

 // 4. Initialize the platform client with this specific http client
 // Note: The constructor accepts the OAuth object. 
 // You must set the http client on the instance, not the static class.
 this.client = new PureCloudPlatformClientV2(oAuth);
 
 // This is the critical part. Set it on the INSTANCE, not PlatformClient.
 // The PureCloudPlatformClientV2 class has a setter for this in newer SDK versions
 // or you might need to access the underlying rest client depending on the exact jar version.
 // If setHttpClient is missing on the instance, you may need to use the RestClient directly 
 // and bypass the high-level api client for bulk endpoints.
 
 // Fallback if the high-level client doesn't expose the setter cleanly:
 // Use RestClient.create(config) as shown in your other post, but ensure 
 // each thread gets its own RestClient instance with its own pool config.
 }

 public void processInteractions() {
 // Use this.client.interactionsApi() here
 // Each thread has its own isolated pool. No ConcurrentModificationException.
 }
}

if the PureCloudPlatformClientV2 instance doesn’t expose setHttpClient in your specific SDK version, drop down to the RestClient level. create a Configuration object, inject your pooled PoolingHttpClientConnectionManager into a custom HttpClient, and pass that to RestClient.create(config). then use the raw ApiClient from that RestClient to make the HTTP calls directly to /api/v2/interactions/endpoint. it’s more boilerplate but it gives you full control over the thread safety. don’t fight the singleton. isolate the connections.

Honestly, that singleton approach is a headache. I usually just spin up a fresh PlatformClient per thread using PureCloudPlatformClientV2. It’s cleaner and avoids the concurrency mess. Just make sure you’re caching the OAuth token properly so you aren’t hitting the auth endpoint for every single request.

PlatformClient client = new PureCloudPlatformClientV2();
client.setHttpClient(customHttpClient);


Yeah, that singleton trap is a real pain. The suggestion above about instantiating per-thread is solid, but you still need to hook that custom client correctly. The `Configuration.Builder` is indeed immutable once you call build, so you can't inject the pool there. You have to grab the `PlatformClient` instance first. Just create a new `PureCloudPlatformClientV2` object for your thread context. Then you can call `setHttpClient` directly on that instance before you make any API calls.

Make sure you close the client when the thread finishes though. If you leave those connections hanging, you'll see state drift in your infrastructure logs later. It's messy if you don't clean up the resources properly. I've seen too many teams forget to shut down the pool and end up with port exhaustion. Just wrap it in a try-with-resources block or a finally clause. It's a bit more boilerplate than the global singleton, but it actually works under load.