Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuring Retry Policies

The Google Cloud client libraries for Rust can automatically retry operations that fail due to transient errors.

This guide shows you how to customize the retry loop. First you'll learn how to enable a common retry policy for all requests in a client, and then how to override this default for a specific request.

Prerequisites

The guide uses the Secret Manager service. That makes the examples more concrete and therefore easier to follow. With that said, the same ideas work for any other service.

You may want to follow the service quickstart. This guide will walk you through the steps necessary to enable the service, ensure you have logged in, and that your account has the necessary permissions.

Dependencies

As usual with Rust, you must declare dependencies in your Cargo.toml file:

cargo add google-cloud-secretmanager-v1

Configuring the default retry policy

This example uses the Aip194Strict policy. This policy is based on the guidelines in AIP-194, which documents the conditions under which a Google API client should automatically retry a request. The policy is fairly conservative, and will not retry any error that indicates the request may have reached the service, unless the request is idempotent. As such, the policy is safe to use as a default. The only downside may be additional requests to the service, consuming some quota and billing.

To make this the default policy for the service, set the policy during the client initialization:

    let client = secret_manager::client::SecretManagerService::builder()
        .with_retry_policy(Aip194Strict)
        .build()
        .await?;

Then use the service as usual:

    let mut list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_item();
    while let Some(secret) = list.next().await {
        let secret = secret?;
        println!("  secret={}", secret.name);
    }

See below for the complete code.

Configuring the default retry policy with limits

The Aip194Strict policy does not limit the number of retry attempts or the time spent retrying requests. However, it can be decorated to set such limits. For example, you can limit both the number of attempts and the time spent in the retry loop using:

    let client = secret_manager::client::SecretManagerService::builder()
        .with_retry_policy(
            Aip194Strict
                .with_attempt_limit(5)
                .with_time_limit(Duration::from_secs(15)),
        )
        .build()
        .await?;

Requests work as usual too:

    let mut list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_item();
    while let Some(secret) = list.next().await {
        let secret = secret?;
        println!("  secret={}", secret.name);
    }

See below for the complete code.

Override the retry policy for one request

Sometimes applications need to override the retry policy for a specific request. For example, the application developer may know specific details of the service or application and determine it is safe to tolerate more errors.

For example, deleting a secret is idempotent, because it can only succeed once. But the client library assumes all delete operations are unsafe. The application can override the policy for one request:

    client
        .delete_secret()
        .set_name(format!("projects/{project_id}/secrets/{secret_id}"))
        .with_retry_policy(
            AlwaysRetry
                .with_attempt_limit(5)
                .with_time_limit(Duration::from_secs(15)),
        )
        .send()
        .await?;

See below for the complete code.

Configuring the default retry policy: complete code

pub async fn client_retry(project_id: &str) -> crate::Result<()> {
    use google_cloud_gax::paginator::ItemPaginator as _;
    use google_cloud_gax::retry_policy::Aip194Strict;
    use google_cloud_secretmanager_v1 as secret_manager;

    let client = secret_manager::client::SecretManagerService::builder()
        .with_retry_policy(Aip194Strict)
        .build()
        .await?;

    let mut list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_item();
    while let Some(secret) = list.next().await {
        let secret = secret?;
        println!("  secret={}", secret.name);
    }

    Ok(())
}

Configuring the default retry policy with limits: complete code

pub async fn client_retry_full(project_id: &str) -> crate::Result<()> {
    use google_cloud_gax::paginator::ItemPaginator as _;
    use google_cloud_gax::retry_policy::Aip194Strict;
    use google_cloud_gax::retry_policy::RetryPolicyExt;
    use google_cloud_secretmanager_v1 as secret_manager;
    use std::time::Duration;

    let client = secret_manager::client::SecretManagerService::builder()
        .with_retry_policy(
            Aip194Strict
                .with_attempt_limit(5)
                .with_time_limit(Duration::from_secs(15)),
        )
        .build()
        .await?;

    let mut list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_item();
    while let Some(secret) = list.next().await {
        let secret = secret?;
        println!("  secret={}", secret.name);
    }

    Ok(())
}

Override the retry policy for one request: complete code

use google_cloud_secretmanager_v1 as secret_manager;
pub async fn request_retry(
    client: &secret_manager::client::SecretManagerService,
    project_id: &str,
    secret_id: &str,
) -> crate::Result<()> {
    use google_cloud_gax::options::RequestOptionsBuilder;
    use google_cloud_gax::retry_policy::AlwaysRetry;
    use google_cloud_gax::retry_policy::RetryPolicyExt;
    use std::time::Duration;

    client
        .delete_secret()
        .set_name(format!("projects/{project_id}/secrets/{secret_id}"))
        .with_retry_policy(
            AlwaysRetry
                .with_attempt_limit(5)
                .with_time_limit(Duration::from_secs(15)),
        )
        .send()
        .await?;

    Ok(())
}