Gerenciar operações de longa duração

Cloud de Confiance by S3NS As APIs usam operações de longa duração (LROs, na sigla em inglês) para chamadas que levam muito tempo para serem concluídas. Por exemplo, provisionar uma instância do Compute Engine ou inicializar um pipeline do Dataflow. Essas APIs não mantêm uma conexão ativa de longa duração nem bloqueiam enquanto a tarefa é executada. Para APIs de LRO, as bibliotecas de cliente do Cloud para Java retornam um future para você verificar mais tarde.

Como determinar se uma API é uma LRO

Há duas maneiras principais de determinar se uma API é uma LRO:

  • As APIs de LRO têm o sufixo Async (por exemplo, createClusterAsync) ou OperationCallable (por exemplo, createClusterOperationCallable).
  • As APIs de LRO retornam um OperationFuture ou OperationCallable.

O snippet a seguir mostra as duas variações, usando Java-Dataproc como exemplo:

// Async suffix (#1) returns OperationFuture (#2)
public final OperationFuture<Cluster, ClusterOperationMetadata> createClusterAsync(CreateClusterRequest request)

// OperationCallable suffix (#1) returns OperationCallable (#2)
public final OperationCallable<CreateClusterRequest, Cluster, ClusterOperationMetadata> createClusterOperationCallable()

Essas são duas variações da mesma API e não duas APIs diferentes. Ambas as chamadas criam um cluster do Dataproc. A variante Async é recomendada.

Fluxo geral de uma LRO

As APIs de LRO são essencialmente uma chamada de solicitação inicial seguida por uma série de pequenas chamadas de pesquisa. A chamada inicial envia a solicitação e cria uma "operação" no servidor. Todas as chamadas de pesquisa subsequentes para o servidor rastreiam o status da operação. Se a operação for concluída, a resposta será retornada. Caso contrário, um status incompleto será retornado e a biblioteca de cliente determinará se deve pesquisar novamente.

Por padrão, o cliente processa a lógica de pesquisa, e você não precisa configurar o mecanismo de pesquisa, a menos que tenha requisitos específicos.

Do seu ponto de vista, a chamada é executada em segundo plano até que uma resposta seja recebida. As chamadas de pesquisa e as configurações de tempo limite têm valores padrão pré-configurados pela equipe de serviço com base no tempo esperado para as APIs. Essas configurações controlam muitos fatores, como a frequência de pesquisa e o tempo de espera antes de desistir.

As bibliotecas de cliente do Cloud para Java fornecem uma interface para interagir com a LRO usando OperationFuture.

O snippet a seguir mostra como chamar uma operação e aguardar uma resposta, usando Java-Dataproc como exemplo:

try (ClusterControllerClient clusterControllerClient = ClusterControllerClient.create()) {
  CreateClusterRequest request =
      CreateClusterRequest.newBuilder().build();
  OperationFuture<Cluster, ClusterOperationMetadata> future =
      clusterControllerClient.createClusterAsync(request);
  // Blocks until there is a response
  Cluster response = future.get();
} catch (CancellationException e) {
  // Exceeded the timeout without the Operation completing.
  // Library is no longer polling for the Operation's status.
}

Valores padrão de LRO

Você pode encontrar os valores padrão na classe StubSettings de cada cliente. O método initDefaults() inicializa as configurações de LRO na classe Builder aninhada.

Por exemplo, no Java-Aiplatform v3.24.0, a chamada de LRO deployModel tem os seguintes parâmetros padrão:

OperationTimedPollAlgorithm.create(
  RetrySettings.newBuilder()
    .setInitialRetryDelayDuration(Duration.ofMillis(5000L))
    .setRetryDelayMultiplier(1.5)
    .setMaxRetryDelayDuration(Duration.ofMillis(45000L))
    .setTotalTimeoutDuration(Duration.ofMillis(300000L))
    .setInitialRpcTimeoutDuration(Duration.ZERO) // not used
    .setRpcTimeoutMultiplier(1.0) // not used
    .setMaxRpcTimeoutDuration(Duration.ZERO) // not used
    .build()));

As novas tentativas e as LROs compartilham a mesma classe RetrySettings. A tabela a seguir mostra o mapeamento entre os campos dentro de RetrySettings e a funcionalidade de LRO:

RetrySettings Descrição
InitialRetryDelay Atraso inicial antes da primeira sondagem.
MaxRetryDelay Atraso máximo entre cada pesquisa.
RetryDelayMultiplier Multiplicador para o atraso de nova tentativa de sondagem entre sondagens.
TotalTimeoutDuration Tempo máximo permitido para a operação de longa duração.

Quando configurar valores de LRO

O principal caso de uso para configurar manualmente os valores de LRO é modificar as frequências de pesquisa devido a tempos limite de LRO. Embora os valores padrão sejam configurados como uma estimativa pela equipe de serviço, alguns fatores podem resultar em tempos limite ocasionais.

Para reduzir o número de tempos limite, aumente o valor total do tempo limite. Aumentar os outros valores também pode ajudar, e você precisa testá-los para garantir o comportamento esperado.

Como configurar valores de LRO

Para configurar os valores de LRO, crie um objeto OperationTimedPollAlgorithm e atualize o algoritmo de pesquisa para uma LRO específica. O snippet a seguir usa Java-Dataproc como exemplo:

ClusterControllerSettings.Builder settingsBuilder = ClusterControllerSettings.newBuilder();
// Create a new OperationTimedPollAlgorithm object
TimedRetryAlgorithm timedRetryAlgorithm = OperationTimedPollAlgorithm.create(
  RetrySettings.newBuilder()
    .setInitialRetryDelayDuration(Duration.ofMillis(500L))
    .setRetryDelayMultiplier(1.5)
    .setMaxRetryDelayDuration(Duration.ofMillis(5000L))
    .setTotalTimeoutDuration(Duration.ofHours(24L))
    .build());
// Set the new polling settings for the specific LRO API 
settingsBuilder.createClusterOperationSettings().setPollingAlgorithm(timedRetryAlgorithm);
ClusterControllerClient clusterControllerClient = ClusterControllerClient.create(settingsBuilder.build());

Essa configuração modifica apenas os valores de LRO para a RPC createClusterOperation. As outras RPCs no cliente ainda usam os valores de LRO pré-configurados para cada RPC, a menos que também sejam modificadas.

Tempos limite de LRO

A biblioteca continua pesquisando enquanto o tempo limite total não for excedido. Se o tempo limite total for excedido, a biblioteca vai gerar uma java.util.concurrent.CancellationException com a mensagem "Task was cancelled" (Tarefa foi cancelada).

Uma CancellationException não significa que a tarefa de back-end Cloud de Confiance by S3NS foi cancelada. Essa exceção é gerada na biblioteca de cliente quando uma chamada excede o tempo limite total e não recebe uma resposta. Mesmo que a tarefa seja concluída imediatamente após o tempo limite, a resposta não será vista pela biblioteca de cliente.