管理长时间运行的操作

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(这两个调用都会创建 Managed Service for Apache Spark 集群)。建议使用 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,并显示消息“Task was cancelled.”(任务已取消)。

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