配置轮询政策

了解如何为长时间运行的操作配置轮询政策。适用于 Rust 的Google Cloud 客户端库提供了辅助函数,可简化长时间运行的操作 (LRO) 的进度监控。这些辅助程序使用政策来配置轮询频率,并确定哪些轮询错误是暂时性的(可以安全地重试),哪些是无法恢复的。

以下两项政策可控制 LRO 循环的行为:

  • 轮询退避政策用于控制循环在轮询仍在进行中的 LRO 的状态之前等待的时间。
  • 轮询错误政策用于控制在出现轮询错误时应执行的操作。某些轮询错误是无法恢复的,表示操作已中止或调用者无权检查 LRO 的状态。其他轮询错误是暂时性的,表示客户端网络或服务中存在临时问题。

您可以单独设置每项政策。此外,您还可以对客户端上启动的所有 LRO 应用政策,或更改单个请求的政策。

前提条件

本指南使用 Cloud Storage 服务来使代码段具体化,但相同的概念适用于使用 LRO 的任何其他服务。

在使用本指南之前,请按照将 Cloud Storage 与 Rust 搭配使用中的说明启用 Cloud Storage API 并对其进行身份验证。

如需查看 Rust 库的完整设置说明,请参阅设置开发环境

依赖项

将以下依赖项添加到您的 Cargo.toml 文件中:

cargo add google-cloud-storage google-cloud-lro

为客户端中的所有请求配置轮询频率

如果您打算对同一客户端的大多数请求使用相同的轮询退避政策,请考虑将该政策设置为客户端选项。此代码示例会为向 Cloud Storage 服务发出的所有请求配置轮询频率。

pub async fn client_backoff(bucket: &str, folder: &str, dest: &str) -> Result<()> {
    // Use a type that implements the `PollingBackoffPolicy` trait, in this case
    // `ExponentialBackoffBuilder`.
    use google_cloud_gax::exponential_backoff::ExponentialBackoffBuilder;
    use google_cloud_lro::Poller;
    use std::time::Duration;

    let client = StorageControl::builder()
        // Initialize the policy with a chosen delay duration.
        .with_polling_backoff_policy(
            ExponentialBackoffBuilder::new()
                .with_initial_delay(Duration::from_millis(250))
                .with_maximum_delay(Duration::from_secs(10))
                .build()?,
        )
        .build()
        .await?;

    // Initiate an LRO using polling.
    let response = client
        .rename_folder()
        .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
        .set_destination_folder_id(dest)
        .poller()
        .until_done()
        .await?;

    println!("LRO completed, response={response:?}");

    Ok(())
}

除非您使用每个请求的设置替换该政策,否则该政策将对客户端启动的任何长时间运行的操作保持有效。

例如,以下调用将使用此政策:

    let mut operation = client
        .rename_folder()
        /* more stuff */
        .send()
        .await?;

在此示例调用中,客户端库在第一次轮询尝试后等待 250 毫秒,然后在第二次尝试后等待 500 毫秒。后续尝试会等待 1 秒、2 秒、4 秒和 8 秒,然后所有进一步的尝试都会等待 10 秒。

为特定请求配置轮询频率

您可以为单个请求配置轮询频率,这会替换客户端级设置的所有政策。例如:

pub async fn rpc_backoff(bucket: &str, folder: &str, dest: &str) -> Result<()> {
    // Use a type that implements the `PollingBackoffPolicy` trait, in this case
    // `ExponentialBackoffBuilder`.
    use google_cloud_gax::exponential_backoff::ExponentialBackoffBuilder;
    use std::time::Duration;

    // To configure the request, bring the RequestOptionsBuilder trait into
    // scope.
    use google_cloud_gax::options::RequestOptionsBuilder;
    use google_cloud_lro::Poller;

    let client = StorageControl::builder().build().await?;
    // Create the request builder.
    let response = client
        .rename_folder()
        // Configure the polling backoff policy.
        .with_polling_backoff_policy(
            ExponentialBackoffBuilder::new()
                .with_initial_delay(Duration::from_millis(250))
                .with_maximum_delay(Duration::from_secs(10))
                .build()?,
        )
        .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
        .set_destination_folder_id(dest)
        // Issue the polling request as normal.
        .poller()
        .until_done()
        .await?;

    println!("LRO completed, response={response:?}");

    Ok(())
}

为客户端中的所有请求配置可重试的轮询错误

如需配置可重试的错误,请使用实现 PollingErrorPolicy 特征的类型。客户端库提供了多种政策;保守的选择是 Aip194Strict。如果您打算对同一客户端的大多数请求使用相同的轮询政策,请考虑将该政策设置为客户端选项。

此代码示例为对 Cloud Storage 服务的所有请求配置了可重试的轮询错误:

pub async fn client_error_policy(bucket: &str, folder: &str, dest: &str) -> Result<()> {
    // Use a type that implements the `PollingErrorPolicy` trait, in this case
    // `Aip194Strict`.
    use google_cloud_gax::polling_error_policy::Aip194Strict;
    use google_cloud_gax::polling_error_policy::PollingErrorPolicyExt;
    use google_cloud_lro::Poller;
    use std::time::Duration;

    // Add the polling policy that you want to use for all long-running
    // operations.
    let client = StorageControl::builder()
        .with_polling_error_policy(
            Aip194Strict
                .with_attempt_limit(100)
                .with_time_limit(Duration::from_secs(300)),
        )
        .build()
        .await?;

    // Initiate an LRO using polling.
    let response = client
        .rename_folder()
        .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
        .set_destination_folder_id(dest)
        .poller()
        .until_done()
        .await?;

    println!("LRO completed, response={response:?}");

    Ok(())
}

虽然轮询错误政策可以处理 LRO 等待循环期间的错误,但您也可以添加标准重试政策来处理在最初发送请求以启动 LRO 时可能发生的暂时性错误:

    let client = StorageControl::builder()
        .with_retry_policy(
            retry_policy::Aip194Strict
                .with_attempt_limit(100)
                .with_time_limit(Duration::from_secs(300)),
        )
        .build()
        .await?;

除非您使用按请求设置替换该政策,否则该政策将对客户端启动的任何长时间运行的操作保持有效。例如,如果您进行以下调用:

    let mut operation = client
        .rename_folder()
        /* more stuff */
        .send()
        .await?;

注意:客户端库仅将 UNAVAILABLE(请参阅 AIP-194)视为可重试的错误,并在尝试 100 次或 300 秒后(以先到者为准)停止轮询。

为特定请求配置可重试的轮询错误

您可以使用实现 PollingErrorPolicy 特征的类型,并将 RequestOptionsBuilder 特征纳入范围,为特定请求配置可重试的轮询错误。

此代码示例为向 Cloud Storage 服务发出的特定请求配置了可重试的轮询错误。

pub async fn rpc_error_policy(bucket: &str, folder: &str, dest: &str) -> Result<()> {
    // Use a type that implements the `PollingErrorPolicy` trait, in this case
    // `Aip194Strict`.
    use google_cloud_gax::polling_error_policy::Aip194Strict;
    use google_cloud_gax::polling_error_policy::PollingErrorPolicyExt;
    // Bring `RequestOptionsBuilder` into scope.
    use google_cloud_gax::options::RequestOptionsBuilder;
    use std::time::Duration;
    use google_cloud_lro::Poller;

    let client = StorageControl::builder().build().await?;

    // Create the request builder.
    let response = client
        .rename_folder()
        // Configure the polling error policy.
        .with_polling_error_policy(
            Aip194Strict
                .with_attempt_limit(100)
                .with_time_limit(Duration::from_secs(300)),
        )
        .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
        .set_destination_folder_id(dest)
        // Initialize the request.
        .poller()
        .until_done()
        .await?;

    println!("LRO completed, response={response:?}");

    Ok(())
}

您还可以考虑添加重试政策,以防启动 LRO 的初始请求失败:

    let client = StorageControl::builder()
        .with_retry_policy(
            retry_policy::Aip194Strict
                .with_attempt_limit(100)
                .with_time_limit(Duration::from_secs(300)),
        )
        .build()
        .await?;