Gerenciar ciclos de vida de clientes nas bibliotecas de cliente do Cloud para Java

As instâncias da biblioteca de cliente são reutilizáveis e projetadas para serem de longa duração. Normalmente, os aplicativos mantêm uma única instância de uma biblioteca de cliente, em vez de criar uma biblioteca para cada solicitação.

Usando o Java-KMS como exemplo, o snippet a seguir mostra várias solicitações sendo invocadas com a mesma instância de cliente:

// 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();

Fechar um cliente

A maneira como você gerencia o ciclo de vida de um cliente pode depender do caso de uso e da biblioteca de cliente específica. Por exemplo, se você estiver usando um framework, siga as diretrizes dele para gerenciamento de clientes. Embora alguns cenários possam usar try-with-resources para clientes de curta duração, geralmente é recomendável reutilizar uma instância de cliente de longa duração para eficiência.

Chamar close() em um cliente tenta um desligamento ordenado e garante que as tarefas atuais continuem até a conclusão. O cliente não aceitará novas tarefas. Se você não fechar o cliente, os recursos dele vão continuar persistindo, e o aplicativo vai gerar vazamentos de memória.

O exemplo a seguir usa o Java-KMS e mostra o cliente sendo fechado:

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();

Além de close(), algumas bibliotecas de cliente Java expõem alguns métodos relacionados para gerenciar o ciclo de vida do cliente:

  • shutdown(): equivalente a close().
  • shutdownNow(): invoca o processo de desligamento imediatamente. Interrompe todas as tarefas em execução e não espera que a tarefa seja concluída.
  • isShutdown(): retorna true se as tarefas em segundo plano tiverem sido desligadas.
  • isTerminated(): retorna true se todas as tarefas tiverem sido concluídas após o desligamento.
  • awaitTermination(): bloqueia por um período até que todo o trabalho seja concluído após o desligamento.

Casos para vários clientes

Pode haver casos de uso específicos do cliente que justifiquem várias instâncias coexistentes de uma biblioteca de cliente. O principal caso de uso para ter vários clientes é quando há solicitações que precisam ser enviadas para vários endpoints diferentes. Uma instância de cliente se conecta a um único endpoint. Para se conectar a vários endpoints, crie um cliente para cada um.

Possíveis riscos de vários clientes

Há alguns riscos comuns com aplicativos que usam várias instâncias de biblioteca de cliente:

  • Maior potencial de vazamentos de memória. Os recursos permanecem se nem todas as instâncias de cliente forem fechadas corretamente.
  • Implicações de desempenho. A inicialização de vários canais gRPC gera um custo de desempenho, que pode aumentar em aplicativos sensíveis ao desempenho.
  • Problemas com solicitações em trânsito. Fechar um cliente enquanto as solicitações ainda estão em trânsito pode levar a uma RejectedExecutionException. Garanta que as solicitações sejam concluídas antes de fechar o cliente.