Client library instances are reusable and designed to be long-lived. Typically, applications maintain a single instance of a client library, rather than creating a library for each request.
Using Java-KMS as an example, the following snippet shows multiple requests being invoked with the same client instance:
// Create one instance of KMS's KeyManagementServiceClient
KeyManagementServiceClient keyManagementServiceClient =
KeyManagementServiceClient.create();
keyManagementServiceClient.listKeyRings();
keyManagementServiceClient.asymmetricSign();
keyManagementServiceClient.createCryptoKey();
// ... other code ...
// Create one instance of KMS's AutokeyClient
AutokeyClient autokeyClient = AutokeyClient.create();
autokeyClient.listKeyHandles();
autokeyClient.getKeyHandle();
Close a client
How you manage a client's lifecycle can depend on the use case and the specific
client library. For example, if you're using a framework, follow the
framework's guidelines for client management. While some scenarios might use
try-with-resources
for shorter-lived clients, reusing a long-lived client
instance is generally recommended for efficiency
Calling close()
on a client attempts an orderly shutdown and ensures that
existing tasks continue until completion. The client won't accept new tasks. If
you don't close the client, its resources continue to persist, and your
application incurs memory leaks.
The following example uses Java-KMS and shows the client being closed:
KeyManagementServiceClient keyManagementServiceClient =
KeyManagementServiceClient.create(keyManagementServiceSettings);
// ... other code ...
keyManagementServiceClient.close();
// For gRPC clients, it's recommended to call awaitTermination to ensure a
// graceful shutdown and avoid the following error message in the logs:
// ERROR i.g.i.ManagedChannelOrphanWrapper - *~*~*~ Channel ManagedChannelImpl
// was not shutdown properly!!! ~*~*~*
// java.lang.RuntimeException: ManagedChannel allocation site
// at io.grpc.internal.ManagedChannelOrphanWrapper$ManagedChannelReference.<init>
keyManagementServiceClient.awaitTermination(DURATION, TimeUnit.SECONDS);
// Optionally include a shutdownNow() call after awaitTermination() to force
// close any lingering resources
keyManagementServiceClient.shutdownNow();
In addition to close()
, some Java client libraries expose a few related
methods for managing the client lifecycle:
shutdown()
: Equivalent toclose()
.shutdownNow()
: Invokes the shutdown process immediately. Stops all executing tasks and doesn't wait for the task to complete.isShutdown()
: Returnstrue
if the background tasks have been shut down.isTerminated()
: Returnstrue
if all tasks have completed following shutdown.awaitTermination()
: Blocks for a duration until all work has completed following shutdown.
Cases for multiple clients
There can be specific customer use cases that warrant multiple co-existing instances of a client library. The main use case for having multiple clients is when there are requests that must be sent to multiple different endpoints. A client instance connects to a single endpoint. To connect to multiple endpoints, create a client for each.
Potential multi-client risks
There are a few common risks with applications using multiple client library instances:
- Increased potential for memory leaks. Resources linger if not all client instances are properly closed.
- Performance implications. Initializing multiple gRPC channels incurs a performance cost, which can add up in performance-sensitive applications.
- Issues with in-flight requests. Closing a client while requests are
still in-flight can lead to a
RejectedExecutionException
. Ensure requests complete before closing the client.