Occasionally, an API might expose a method that takes a significant amount of time to complete. Instead of blocking while the task runs, you can return a promise and let the user check the status.
The Google Cloud Client Libraries for Rust provide helpers to work with these long-running operations (LROs). This guide shows you how to start LROs and wait for their completion.
Prerequisites
This guide uses the Cloud Storage service to keep the code snippets concrete. These concepts apply to any other service that uses LROs.
Before following this guide, you should:
- Create a Google Cloud project.
- Enable billing.
For complete setup instructions for the Rust libraries, see Setting up your development environment.
Dependencies
Declare Google Cloud dependencies in your Cargo.toml file:
cargo add google-cloud-storage google-cloud-lro google-cloud-longrunning
You also need several tokio features:
cargo add tokio --features full,macros
Start a long-running operation
This example uses rename folder. This operation can take a long time for large folders, but it is relatively fast for smaller folders.
To start a long-running operation, you must initialize a client and make the RPC.
First, add use declarations to avoid long package names:
Next, create the client:
In the Rust client libraries, each request is represented by a method that returns a request builder. Call the method on the client to create the request builder:
The sample functions accept the bucket and folder names as arguments:
Make the request and wait for an Operation to
be returned. This Operation acts as a promise for the result of the
long-running request:
let operation =
// ...
.send()
.await?;
This request starts the operation in the background. Wait until the operation completes to determine if it was successful.
Automatically poll a long-running operation
To configure automatic polling, you will
Start a long-running operation with
a Poller rather than .send().wait, like so:
First, introduce the Poller trait in scope using a use declaration:
Then initialize the client and prepare the request as before:
Poll until the operation completes and print the result:
.poller()
.until_done()
.await?;
println!("LRO completed, response={response:?}");
Poll a long-running operation with intermediate results
The .until_done() method is convenient, but it omits partial progress reports
from long-running operations. If your application requires this information, use
the poller directly:
let mut poller = client
.rename_folder()
/* more stuff */
.poller();
Then use the poller in a loop:
This loop explicitly waits before polling again. The polling period depends on the specific operation and its payload. Consult the service documentation or experiment with your data to determine a good value.
Manually poll a long-running operation
While we recommend automated polling approaches, it's also possible to manually poll a long-running operation. For more information, see the Operation message reference documentation.
Start the long-running operation using the client:
let mut operation = client
.rename_folder()
/* more stuff */
.send()
.await?;
Start a polling loop, and check if the operation completed using
the done field:
When the operation completes, it usually contains a result. The result field is
optional because the service could return done as true without a result. For
example, a successful deletion operation has no return value. In this example,
the Cloud Storage service always returns a value:
A started operation might not complete successfully. The result can be an error or a valid response. Check for errors first:
The error type is a Status message type. This does NOT
implement the standard Error trait. Manually convert it to a
valid error using Error::service.
If the result is successful, extract the response type. Find this type in the LRO method documentation or the service API documentation:
Note that extraction of the value may fail if the type does not match what the service sent.
Google Cloud types might add fields and branches in the future. The Google Cloud
Client Libraries for Rust mark all structs and enums as #[non_exhaustive].
Handle this case:
If the operation hasn't completed, it might contain metadata. Some services include initial information about the request, while other services include partial progress reports. You can extract and report this metadata:
Wait before polling again. Consider adjusting the polling period using truncated exponential backoff. This example polls every 500ms:
Query the operation status:
For simplicity, this example ignores all errors. In your application, you can treat a subset of errors as non-recoverable and limit the number of polling attempts.
What's next
- View the source code for the examples on GitHub.