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 会返回
OperationFuture或OperationCallable。
以下代码段以 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
任务已取消。当调用超出总超时时间且未收到响应时,客户端库会抛出此异常。即使任务在超时后立即完成,客户端库也不会看到响应。