Bekerja dengan operasi yang berjalan lama

Terkadang, API dapat mengekspos metode yang memerlukan waktu lama untuk diselesaikan. Daripada memblokir saat tugas berjalan, Anda dapat menampilkan promise dan membiarkan pengguna memeriksa statusnya.

Google Cloud Client Libraries for Rust menyediakan helper untuk menangani operasi yang berjalan lama (LRO). Panduan ini menunjukkan cara memulai LRO dan menunggu penyelesaiannya.

Prasyarat

Panduan ini menggunakan layanan Cloud Storage untuk menjaga agar cuplikan kode tetap konkret. Konsep ini berlaku untuk layanan lain yang menggunakan LRO.

Sebelum mengikuti panduan ini, Anda harus:

Untuk mengetahui petunjuk penyiapan lengkap untuk library Rust, lihat Menyiapkan lingkungan pengembangan Anda.

Dependensi

Mendeklarasikan dependensi Google Cloud dalam file Cargo.toml Anda:

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

Anda juga memerlukan beberapa fitur tokio:

cargo add tokio --features full,macros

Memulai operasi yang berjalan lama

Contoh ini menggunakan rename folder. Operasi ini dapat memerlukan waktu yang lama untuk folder besar, tetapi relatif cepat untuk folder yang lebih kecil.

Untuk memulai operasi yang berjalan lama, Anda harus melakukan inisialisasi klien dan membuat RPC.

Pertama, tambahkan deklarasi use untuk menghindari nama paket yang panjang:

use anyhow::anyhow;
use google_cloud_longrunning as longrunning;
use google_cloud_storage::client::StorageControl;

Selanjutnya, buat klien:

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

Di library klien Rust, setiap permintaan diwakili oleh metode yang menampilkan pembuat permintaan. Panggil metode pada klien untuk membuat builder permintaan:

let operation = client
    .rename_folder()
    .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
    .set_destination_folder_id(dest)

Fungsi contoh menerima nama bucket dan folder sebagai argumen:

pub async fn manual(bucket: &str, folder: &str, dest: &str) -> anyhow::Result<()> {

Buat permintaan dan tunggu hingga Operation ditampilkan. Operation ini bertindak sebagai janji untuk hasil permintaan yang berjalan lama:

    let operation =
        // ...
        .send()
        .await?;

Permintaan ini memulai operasi di latar belakang. Tunggu hingga operasi selesai untuk menentukan apakah operasi berhasil.

Melakukan polling operasi yang berjalan lama secara otomatis

Untuk mengonfigurasi polling otomatis, Anda akan Memulai operasi yang berjalan lama dengan Poller, bukan .send().wait, seperti berikut:

.poller()
.until_done()
.await?;

Pertama, perkenalkan trait Poller dalam cakupan menggunakan deklarasi use:

use google_cloud_lro::Poller;

Kemudian, lakukan inisialisasi klien dan siapkan permintaan seperti sebelumnya:

let response = client
    .rename_folder()
    .set_name(format!("projects/_/buckets/{bucket}/folders/{folder}"))
    .set_destination_folder_id(dest)

Lakukan polling hingga operasi selesai dan cetak hasilnya:

    .poller()
    .until_done()
    .await?;

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

Melakukan polling operasi yang berjalan lama dengan hasil sementara

Metode .until_done() memang praktis, tetapi tidak menyertakan laporan progres parsial dari operasi yang berjalan lama. Jika aplikasi Anda memerlukan informasi ini, gunakan poller secara langsung:

    let mut poller = client
        .rename_folder()
        /* more stuff */
        .poller();

Kemudian, gunakan poller dalam loop:

while let Some(p) = poller.poll().await {
    match p {
        PollingResult::Completed(r) => {
            println!("LRO completed, response={r:?}");
        }
        PollingResult::InProgress(m) => {
            println!("LRO in progress, metadata={m:?}");
        }
        PollingResult::PollingError(e) => {
            println!("Transient error polling the LRO: {e}");
        }
    }
    tokio::time::sleep(std::time::Duration::from_millis(500)).await;
}

Loop ini secara eksplisit menunggu sebelum melakukan polling lagi. Periode polling bergantung pada operasi tertentu dan payload-nya. Lihat dokumentasi layanan atau bereksperimen dengan data Anda untuk menentukan nilai yang baik.

Melakukan polling operasi yang berjalan lama secara manual

Meskipun kami merekomendasikan pendekatan polling otomatis, Anda juga dapat melakukan polling operasi yang berjalan lama secara manual. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi pesan Operation.

Mulai operasi yang berjalan lama menggunakan klien:

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

Mulai loop polling, dan periksa apakah operasi selesai menggunakan kolom done:

let response: anyhow::Result<Folder> = loop {
    if operation.done {

Saat operasi selesai, biasanya akan berisi hasil. Kolom hasil bersifat opsional karena layanan dapat menampilkan done sebagai benar tanpa hasil. Misalnya, operasi penghapusan yang berhasil tidak memiliki nilai yang ditampilkan. Dalam contoh ini, layanan Cloud Storage selalu menampilkan nilai:

match &operation.result {
    None => {
        break Err(anyhow!("missing result for finished operation"));
    }

Operasi yang dimulai mungkin tidak berhasil diselesaikan. Hasilnya dapat berupa error atau respons yang valid. Periksa error terlebih dahulu:

Some(r) => {
    break match r {
        longrunning::model::operation::Result::Error(s) => {
            Err(anyhow!("operation completed with error {s:?}"))
        }

Jenis error adalah jenis pesan Status. Hal ini TIDAK menerapkan sifat Error standar. Konversikan secara manual menjadi error yang valid menggunakan Error::service.

Jika hasilnya berhasil, ekstrak jenis respons. Temukan jenis ini dalam dokumentasi metode LRO atau dokumentasi API layanan:

longrunning::model::operation::Result::Response(any) => {
    let response = any.to_msg::<Folder>()?;
    Ok(response)
}

Perhatikan bahwa ekstraksi nilai dapat gagal jika jenisnya tidak cocok dengan yang dikirim oleh layanan.

JenisGoogle Cloud dapat menambahkan kolom dan cabang pada masa mendatang. Library Klien Google Cloud untuk Rust menandai semua struct dan enum sebagai #[non_exhaustive]. Tangani kasus ini:

_ => Err(anyhow!("unexpected result branch {r:?}")),

Jika operasi belum selesai, operasi tersebut mungkin berisi metadata. Beberapa layanan menyertakan informasi awal tentang permintaan, sementara layanan lainnya menyertakan laporan progres sebagian. Anda dapat mengekstrak dan melaporkan metadata ini:

if let Some(any) = &operation.metadata {
    let metadata = any.to_msg::<RenameFolderMetadata>()?;
    println!("LRO in progress, metadata={metadata:?}");
}

Tunggu sebelum melakukan polling lagi. Pertimbangkan untuk menyesuaikan periode polling menggunakan backoff eksponensial yang dipangkas. Contoh ini melakukan polling setiap 500 md:

tokio::time::sleep(std::time::Duration::from_millis(500)).await;

Buat kueri status operasi:

if let Ok(attempt) = client
    .get_operation()
    .set_name(&operation.name)
    .send()
    .await
{
    operation = attempt;
}

Agar mudah, contoh ini mengabaikan semua error. Di aplikasi, Anda dapat memperlakukan subset error sebagai tidak dapat dipulihkan dan membatasi jumlah upaya polling.

Langkah berikutnya

  • Lihat kode sumber untuk contoh di GitHub.