管理长时间运行的操作

Google Cloud 对于预计需要相当长的时间才能完成的调用(例如,预配 Compute Engine 实例或初始化 Dataflow 流水线),API 会使用长时间运行的操作 (LRO)。这些 API 在任务运行时不会保持活跃的长期有效连接或阻塞。对于 LRO API,Java 版 Cloud 客户端库会返回一个 future,供您稍后检查。

确定 API 是否为 LRO

您可以通过以下两种主要方式来确定 API 是否为 LRO:

  • LRO API 的后缀为 Async(例如 createClusterAsync)或 OperationCallable(例如 createClusterOperationCallable)。
  • LRO API 会返回 OperationFutureOperationCallable

以下代码段展示了这两种变体,并以 Java-Dataproc 为例:

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

这两种变体针对的是同一 API,而不是两个不同的 API(两种调用都会创建 Dataproc 集群)。建议使用 Async 变体。

LRO 的高级流程

LRO API 本质上是一个初始请求调用,后跟一系列小型轮询调用。初始调用会发送请求并在服务器上创建“操作”。后续对服务器的所有轮询调用都会跟踪相应操作的状态。如果操作已完成,则返回响应。 否则,系统会返回不完整状态,并且客户端库会确定是否再次轮询。

默认情况下,客户端会处理轮询逻辑,除非您有特殊要求,否则无需配置轮询机制。

从您的角度来看,该调用会在后台运行,直到收到响应为止。轮询调用和超时配置具有默认值,这些默认值由服务团队根据其 API 的预期时间预先配置。这些配置可控制许多因素,例如轮询频率和放弃前的等待时长。

Java 版 Cloud 客户端库提供了一个使用 OperationFuture 与 LRO 交互的接口。

以下代码段展示了如何调用操作并等待响应,以 Java-Dataproc 为例:

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.
}

默认 LRO 值

您可以在每个客户端的 StubSettings 类中找到默认值。initDefaults() 方法用于初始化嵌套 Builder 类中的 LRO 设置。

例如,在 Java-Aiplatform v3.24.0 中,deployModel LRO 调用具有以下默认参数:

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

重试和 LRO 共享相同的 RetrySettings 类。下表显示了 RetrySettings 内的字段与 LRO 功能之间的映射:

RetrySettings 说明
InitialRetryDelay 首次轮询之前的初始延迟时间。
MaxRetryDelay 每次轮询之间的最长延迟时间。
RetryDelayMultiplier 轮询之间轮询重试延迟时间的乘数。
TotalTimeoutDuration 长时间运行的操作可运行的最长时间。

何时配置 LRO 值

手动配置 LRO 值的主要用例是因 LRO 超时而修改轮询频率。虽然默认值由服务团队配置为估计值,但某些因素可能会导致偶尔出现超时。

如需减少超时次数,请增加总超时值。增加其他值也有助于解决此问题,您应测试这些值以确保行为符合预期。

如何配置 LRO 值

如需配置 LRO 值,请创建一个 OperationTimedPollAlgorithm 对象,并更新特定 LRO 的轮询算法。以下代码段以 Java-Dataproc 为例:

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

此配置仅修改 createClusterOperation RPC 的 LRO 值。除非也进行了修改,否则客户端中的其他 RPC 仍会使用为每个 RPC 预配置的 LRO 值。

LRO 超时

只要未超过总超时时间,该库就会继续轮询。如果总超时时间已过,该库会抛出 java.util.concurrent.CancellationException 并显示消息“任务已取消”。

CancellationException 并不意味着后端 Google Cloud任务已被取消。当调用超出总超时时间且未收到响应时,客户端库会抛出此异常。即使任务在超时后立即完成,客户端库也不会看到响应。