Genesys Cloud Java SDK thread safety on pooled RestClient

Seeing sporadic java.lang.IllegalStateException: Connection pool shut down errors in our integration service. We’re using the Genesys Cloud Java SDK v7.x and sharing a single ApiService instance across a fixed thread pool of 50 workers. The assumption is that the underlying OkHttp OkHttpClient is thread-safe, but the logs suggest the connection pool is being torn down while requests are still pending.

Here’s the setup:

ApiClient apiClient = new ApiClient("https://api.mypurecloud.com");
apiClient.setAccessToken(token);
RoutingApi routingApi = new RoutingApi(apiClient);

// Shared across threads
public void processInteraction() {
 try {
 RoutingQueue queue = routingApi.getRoutingQueues(...);
 } catch (ApiException e) {
 log.error("Failed", e);
 }
}

The error happens intermittently after about 10k requests. I’ve checked the SDK source and it looks like ApiClient creates a new OkHttpClient on init. Is there a known issue with connection pool lifecycles in the Java SDK? Or should I be manually managing the OkHttpClient instance and passing it to ApiClient? I don’t see a clear way to inject a custom client without breaking the auth flow. Any pointers on configuring the pool size or timeout settings directly through the SDK?

Don’t share a single client instance across that many threads. You’ll get pool contention and those shutdown errors. Instantiate a new PureCloudPlatformClientV2 per task or use a thread-safe wrapper.

// Bad: static final ApiService api = ...
// Good: create per-thread or use a pool of clients
PureCloudPlatformClientV2 client = new PureCloudPlatformClientV2();
client.setAccessToken(token);
RoutingApi api = new RoutingApi(client);

State drift happens fast if you don’t manage lifecycle properly.

The point above is correct about the risk, but creating a new PureCloudPlatformClientV2 instance per task is a terrible idea. That client holds the OAuth refresh logic and the underlying OkHttpClient with its connection pool. Instantiating it fifty times will burn through your connection limits and cause massive latency spikes. The SDK is designed to be thread-safe once configured, but you have to configure the HTTP client correctly.

The issue usually stems from the default OkHttp settings not matching your thread pool size or timeout expectations. You need to customize the OkHttpClient before passing it to the SDK. Here’s how I handle it in Node, but the Java equivalent is straightforward. You set the max idle connections and keep-alive duration to handle the burst.

In Java, you’d do something like this:

OkHttpClient httpClient = new OkHttpClient.Builder()
 .connectTimeout(30, TimeUnit.SECONDS)
 .readTimeout(30, TimeUnit.SECONDS)
 .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)) // Increase max idle
 .build();

PureCloudPlatformClientV2 client = new PureCloudPlatformClientV2();
client.setHttpClient(httpClient);
client.setAccessToken(token);

Sharing a single PureCloudPlatformClientV2 instance across your 50 threads is actually the correct pattern. Just ensure you aren’t calling close() or shutdown() on the client or the underlying HTTP client while requests are in flight. If you’re seeing “pool shut down,” check if some other part of your code is disposing of the client prematurely. Also, make sure you’re not mixing synchronous and asynchronous calls in a way that blocks the thread pool. The SDK methods return Future objects, so you can submit them to your executor service without blocking. Keep the client singleton, tune the HTTP pool, and you’ll be fine.