Strategia di ripetizione dei tentativi

Questa pagina descrive in che modo gli strumenti di Cloud Storage riprovano le richieste non riuscite e come personalizzare il comportamento dei nuovi tentativi. Inoltre, descrive le considerazioni per i nuovi tentativi di richiesta.

Panoramica

Esistono due fattori che determinano se è sicuro riprovare a inviare una richiesta:

  • La risposta che ricevi dalla richiesta.

  • L'idempotenza della richiesta.

Risposta

La risposta che ricevi dalla richiesta indica se è utile riprovare a inviarla. Le risposte relative a problemi temporanei sono generalmente ripetibili. D'altra parte, la risposta relativa agli errori permanenti indica che devi apportare modifiche, ad esempio modifiche all'autorizzazione o alla configurazione, prima che sia utile riprovare a inviare la richiesta. Le seguenti risposte indicano problemi temporanei che è utile riprovare:

  • Codici di risposta HTTP 408, 429 e 5xx.
  • Timeout dei socket e disconnessioni TCP.

Per saperne di più, consulta lo stato e i codici di errore per JSON e XML.

Idempotenza

Le richieste idempotenti possono essere eseguite ripetutamente senza modificare lo stato finale della risorsa target, ottenendo ogni volta lo stesso stato finale. Ad esempio, le operazioni di elenco sono sempre idempotenti perché queste richieste non modificano le risorse. D'altra parte, la creazione di una nuova notifica Pub/Sub non è mai idempotente, perché crea un nuovo ID notifica ogni volta che la richiesta va a buon fine.

Di seguito sono riportati alcuni esempi di condizioni che rendono un'operazione idempotente:

  • L'operazione ha lo stesso effetto osservabile sulla risorsa target anche se viene richiesta continuamente.

  • L'operazione viene eseguita correttamente una sola volta.

  • L'operazione non ha alcun effetto osservabile sullo stato della risorsa di destinazione.

Quando ricevi una risposta che può essere ritentata, devi considerare l'idempotenza della richiesta, perché la ripetizione di richieste non idempotenti può portare a race condition e altri conflitti.

Idempotenza condizionale

Un sottoinsieme di richieste è idempotente in modo condizionale, il che significa che sono idempotenti solo se includono argomenti facoltativi specifici. Le operazioni per cui è sicuro riprovare in modo condizionale devono essere riprovate per impostazione predefinita solo se la condizione viene soddisfatta. Cloud Storage accetta precondizioni ed ETag come casi di condizione per le richieste.

Idempotenza delle operazioni

La tabella seguente elenca le operazioni di Cloud Storage che rientrano in ogni categoria di idempotenza.

Idempotenza Operazioni
Sempre idempotente
  • Tutte le richieste di recupero ed elenco
  • Inserisci o elimina bucket
  • Testa le policy e le autorizzazioni IAM del bucket
  • Bloccare le policy di conservazione
  • Elimina una chiave HMAC o una notifica Pub/Sub
Idempotente in modo condizionale
  • Richieste di aggiornamento/patch per bucket con IfMetagenerationMatch1 o etag1 come precondizione HTTP
  • Richieste di aggiornamento/patch per gli oggetti con IfMetagenerationMatch1 o etag1 come precondizione HTTP
  • Imposta una policy IAM del bucket con etag1 come precondizione HTTP o nel corpo della risorsa
  • Aggiorna una chiave HMAC con etag1 come precondizione HTTP o nel corpo della risorsa
  • Inserisci, copia, componi o riscrivi oggetti con ifGenerationMatch1
  • Elimina un oggetto con ifGenerationMatch1 (o con un numero di generazione per le versioni degli oggetti)
Mai idempotente
  • Creazione di una chiave HMAC
  • Crea una notifica Pub/Sub
  • Creare, eliminare o inviare richieste di patch/aggiornamento per ACL di bucket e oggetti o ACL di oggetti predefiniti

1 Questo campo è disponibile per l'utilizzo nell'API JSON. Per i campi disponibili per l'utilizzo nelle librerie client, consulta la documentazione della libreria client pertinente.

Come gli strumenti Cloud Storage implementano le strategie di ripetizione

Console

La console Google Cloud invia richieste a Cloud Storage per tuo conto e gestisce l'eventuale backoff necessario.

Riga di comando

I comandi gcloud storage riprovano gli errori elencati nella sezione Risposta senza richiedere ulteriori azioni da parte tua. Potresti dover intervenire per altri errori, ad esempio:

  • Credenziali non valide o autorizzazioni insufficienti.

  • Rete non raggiungibile a causa di un problema di configurazione del proxy.

Per gli errori ritentabili, gcloud CLI ritenta le richieste utilizzando una strategia di backoff esponenziale binario troncato. Il numero predefinito di nuovi tentativi massimi è 32 per gcloud CLI.

Librerie client

C++

Per impostazione predefinita, le operazioni supportano i tentativi per i seguenti codici di errore HTTP, nonché per tutti gli errori socket che indicano che la connessione è stata persa o non è mai stata stabilita correttamente.

  • 408 Request Timeout
  • 429 Too Many Requests
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

Tutte le impostazioni di backoff esponenziale e di nuovi tentativi nella libreria C++ sono configurabili. Se gli algoritmi implementati nella libreria non supportano le tue esigenze, puoi fornire codice personalizzato per implementare le tue strategie.

Impostazione Valore predefinito
Nuovo tentativo automatico Vero
Tempo massimo per riprovare una richiesta 15 minuti
Tempo di attesa iniziale (backoff) 1 secondo
Moltiplicatore del tempo di attesa per iterazione 2
Tempo di attesa massimo 5 minuti

Per impostazione predefinita, la libreria C++ riprova tutte le operazioni con errori riprovabili, anche quelle che non sono mai idempotenti e possono eliminare o creare più risorse se ripetutamente riuscite. Per riprovare solo le operazioni idempotenti, utilizza la classe google::cloud::storage::StrictIdempotencyPolicy.

C#

La libreria client C# utilizza il backoff esponenziale per impostazione predefinita.

Vai

Per impostazione predefinita, le operazioni supportano i tentativi per i seguenti errori:

  • Errori di connessione:
    • io.ErrUnexpectedEOF: questo può verificarsi a causa di problemi di rete temporanei.
    • url.Error contenente connection refused: questo potrebbe verificarsi a causa di problemi di rete temporanei.
    • url.Error contenente connection reset by peer: significa che Google Cloud ha reimpostato la connessione.
    • net.ErrClosed: significa che Google Cloud ha chiuso la connessione.
  • Codici HTTP:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Errori che implementano l'interfaccia Temporary() e forniscono un valore di err.Temporary() == true
  • Uno qualsiasi degli errori precedenti che è stato aggregato utilizzando l'aggregazione degli errori di Go 1.13

Tutte le impostazioni di backoff esponenziale nella libreria Go sono configurabili. Per impostazione predefinita, le operazioni in Go utilizzano le seguenti impostazioni per il backoff esponenziale (i valori predefiniti sono presi da gax):

Impostazione Valore predefinito (in secondi)
Nuovo tentativo automatico True se idempotente
Numero massimo di tentativi Nessun limite
Ritardo iniziale nuovo tentativo 1 secondo
Moltiplicatore del ritardo dei nuovi tentativi 2.0
Ritardo massimo nuovo tentativo 30 secondi
Timeout totale (chunk di caricamento ripristinabile) 32 secondi
Timeout totale (tutte le altre operazioni) Nessun limite

In genere, i nuovi tentativi continuano a tempo indeterminato, a meno che il contesto di controllo non venga annullato, il client non venga chiuso o non venga ricevuto un errore non temporaneo. Per impedire che i tentativi vengano ripetuti, utilizza i timeout del contesto o l'annullamento. L'unica eccezione a questo comportamento si verifica quando esegui caricamenti ripristinabili utilizzando Writer, dove i dati sono di dimensioni sufficienti da richiedere più richieste. In questo scenario, ogni chunk va in timeout e interrompe i nuovi tentativi dopo 32 secondi per impostazione predefinita. Puoi modificare il timeout predefinito cambiando Writer.ChunkRetryDeadline.

Esiste un sottoinsieme di operazioni Go che sono idempotenti in modo condizionale (sicure da riprovare in modo condizionale). Queste operazioni vengono ritentate solo se soddisfano condizioni specifiche:

  • GenerationMatch o Generation

    • È sicuro riprovare se alla chiamata è stata applicata una precondizione GenerationMatch o se è stato impostato ObjectHandle.Generation.
  • MetagenerationMatch

    • È sicuro riprovare se alla chiamata è stata applicata una precondizione MetagenerationMatch.
  • Etag

    • È sicuro riprovare se il metodo inserisce un etag nel corpo della richiesta JSON. Utilizzato solo in HMACKeyHandle.Update quando è stato impostato HmacKeyMetadata.Etag.

RetryPolicy è impostato su RetryPolicy.RetryIdempotent per impostazione predefinita. Consulta Personalizza i tentativi di ripetizione per esempi su come modificare il comportamento predefinito dei tentativi di ripetizione.

Java

Per impostazione predefinita, le operazioni supportano i nuovi tentativi per i seguenti errori:

  • Errori di connessione:
    • Connection reset by peer: significa che Google Cloud ha reimpostato la connessione.
    • Unexpected connection closure: significa che Google Cloud ha chiuso la connessione.
  • Codici HTTP:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Tutte le impostazioni di backoff esponenziale nella libreria Java sono configurabili. Per impostazione predefinita, le operazioni tramite Java utilizzano le seguenti impostazioni per il backoff esponenziale:

Impostazione Valore predefinito (in secondi)
Nuovo tentativo automatico True se idempotente
Numero massimo di tentativi 6
Ritardo iniziale nuovo tentativo 1 secondo
Moltiplicatore del ritardo dei nuovi tentativi 2.0
Ritardo massimo nuovo tentativo 32 secondi
Timeout totale 50 secondi
Timeout RPC iniziale 50 secondi
Moltiplicatore timeout RPC 1.0
Timeout RPC massimo 50 secondi
Timeout connessione 20 secondi
Timeout di lettura 20 secondi

Per saperne di più sulle impostazioni, consulta la documentazione di riferimento di Java per RetrySettings.Builder e HttpTransportOptions.Builder.

Esiste un sottoinsieme di operazioni Java che sono idempotenti in modo condizionale (sicure da riprovare in modo condizionale). Queste operazioni vengono ritentate solo se includono argomenti specifici:

  • ifGenerationMatch o generation

    • È sicuro riprovare se ifGenerationMatch o generation è stato passato come opzione al metodo.
  • ifMetagenerationMatch

    • È sicuro riprovare se ifMetagenerationMatch è stato passato come opzione.

StorageOptions.setStorageRetryStrategy è impostato su StorageRetryStrategy#getDefaultStorageRetryStrategy per impostazione predefinita. Consulta Personalizza i tentativi di ripetizione per esempi su come modificare il comportamento di ripetizione predefinito.

Node.js

Per impostazione predefinita, le operazioni supportano i nuovi tentativi per i seguenti codici di errore:

  • Errori di connessione:
    • EAI_again: si tratta di un errore di ricerca DNS. Per saperne di più, consulta la documentazione di getaddrinfo.
    • Connection reset by peer: Ciò significa che Google Cloud ha reimpostato la connessione.
    • Unexpected connection closure: significa che Google Cloud ha chiuso la connessione.
  • Codici HTTP:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Tutte le impostazioni di backoff esponenziale nella libreria Node.js sono configurabili. Per impostazione predefinita, le operazioni tramite Node.js utilizzano le seguenti impostazioni per il backoff esponenziale:

Impostazione Valore predefinito (in secondi)
Nuovo tentativo automatico True se idempotente
Numero massimo di nuovi tentativi 3
Tempo di attesa iniziale 1 secondo
Moltiplicatore del tempo di attesa per iterazione 2
Tempo di attesa massimo 64 secondi
Scadenza predefinita 600 secondi

Esiste un sottoinsieme di operazioni Node.js che sono idempotenti in modo condizionale (sicure da riprovare in modo condizionale). Queste operazioni vengono ritentate solo se includono argomenti specifici:

  • ifGenerationMatch o generation

    • È sicuro riprovare se ifGenerationMatch o generation è stato passato come opzione al metodo. Spesso, i metodi accettano solo uno di questi due parametri.
  • ifMetagenerationMatch

    • È possibile riprovare se ifMetagenerationMatch è stato passato come opzione.

retryOptions.idempotencyStrategy è impostato su IdempotencyStrategy.RetryConditional per impostazione predefinita. Consulta Personalizza i tentativi di nuovo invio per esempi su come modificare il comportamento predefinito dei tentativi di nuovo invio.

PHP

La libreria client PHP utilizza il backoff esponenziale per impostazione predefinita.

Per impostazione predefinita, le operazioni supportano i nuovi tentativi per i seguenti codici di errore:

  • Errori di connessione:
    • connetion-refused: questo problema può verificarsi a causa di problemi di rete temporanei.
    • connection-reset: Ciò significa che Google Cloud ha reimpostato la connessione.
  • Codici HTTP:
    • 200: per i casi di download parziale
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Alcune impostazioni di backoff esponenziale nella libreria PHP sono configurabili. Per impostazione predefinita, le operazioni tramite PHP utilizzano le seguenti impostazioni per il backoff esponenziale:

Impostazione Valore predefinito (in secondi)
Nuovo tentativo automatico True se idempotente
Ritardo iniziale nuovo tentativo 1 secondo
Moltiplicatore del ritardo dei nuovi tentativi 2.0
Ritardo massimo nuovo tentativo 60 secondi
Timeout richiesta 0 con REST, 60 con gRPC
Numero predefinito di nuovi tentativi 3

Esiste un sottoinsieme di operazioni PHP che sono idempotenti in modo condizionale (ovvero, è sicuro riprovarle in modo condizionale). Queste operazioni vengono riprovate solo se includono argomenti specifici:

  • ifGenerationMatch o generation

    • È sicuro riprovare se ifGenerationMatch o generation è stato passato come opzione al metodo. Spesso, i metodi accettano solo uno di questi due parametri.
  • ifMetagenerationMatch

    • È sicuro riprovare se ifMetagenerationMatch è stato passato come opzione.

Quando crei StorageClient, la strategia StorageClient::RETRY_IDEMPOTENT viene utilizzata per impostazione predefinita. Consulta Personalizza i tentativi di ripetizione per esempi su come modificare il comportamento di ripetizione predefinito.

Python

Per impostazione predefinita, le operazioni supportano i nuovi tentativi per i seguenti codici di errore:

  • Errori di connessione:
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError (solo per le operazioni che recuperano o inviano dati di payload agli oggetti, come caricamenti e download)
    • ConnectionError
    • http.client.ResponseNotReady
    • urllib3.exceptions.TimeoutError
  • Codici HTTP:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

Le operazioni tramite Python utilizzano le seguenti impostazioni predefinite per il backoff esponenziale:

Impostazione Valore predefinito (in secondi)
Nuovo tentativo automatico True se idempotente
Tempo di attesa iniziale 1
Moltiplicatore del tempo di attesa per iterazione 2
Tempo di attesa massimo 60
Scadenza predefinita 120

Oltre alle operazioni Cloud Storage che sono sempre idempotenti, la libreria client Python ritenta automaticamente Objects: insert, Objects: delete e Objects: patch per impostazione predefinita.

Esiste un sottoinsieme di operazioni Python che sono condizionalmente idempotenti (condizionalmente sicure per i nuovi tentativi) quando includono argomenti specifici. Queste operazioni vengono riprovate solo se viene superato un caso di condizione:

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • È sicuro riprovare se generation o if_generation_match è stato passato come argomento al metodo. Spesso i metodi accettano solo uno di questi due parametri.
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • È possibile riprovare se if_metageneration_match è stato passato come argomento al metodo.
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • È sicuro riprovare se il metodo inserisce un etag nel corpo della richiesta JSON. Per HMACKeyMetadata.update(), ciò significa che l'etag deve essere impostato sull'oggetto HMACKeyMetadata stesso. Per il metodo set_iam_policy() su altre classi, ciò significa che l'etag deve essere impostato nell'argomento "policy" passato al metodo.

Ruby

Per impostazione predefinita, le operazioni supportano i nuovi tentativi per i seguenti codici di errore:

  • Errori di connessione:
    • SocketError
    • HTTPClient::TimeoutError
    • Errno::ECONNREFUSED
    • HTTPClient::KeepAliveDisconnected
  • Codici HTTP:
    • 408 Request Timeout
    • 429 Too Many Requests
    • 5xx Server Error

Tutte le impostazioni di backoff esponenziale nella libreria client di Ruby sono configurabili. Per impostazione predefinita, le operazioni tramite la libreria client Ruby utilizzano le seguenti impostazioni per il backoff esponenziale:

Impostazione Valore predefinito
Nuovo tentativo automatico Vero
Numero massimo di nuovi tentativi 3
Tempo di attesa iniziale 1 secondo
Moltiplicatore del tempo di attesa per iterazione 2
Tempo di attesa massimo 60 secondi
Scadenza predefinita 900 secondi

Esiste un sottoinsieme di operazioni Ruby che sono idempotenti in modo condizionale (sicure da riprovare in modo condizionale) quando includono argomenti specifici:

  • if_generation_match o generation

    • È sicuro riprovare se il parametro generation o if_generation_match viene passato come argomento al metodo. Spesso i metodi accettano solo uno di questi due parametri.
  • if_metageneration_match

    • È possibile riprovare se il parametro if_metageneration_match viene trasmesso come opzione.

Per impostazione predefinita, viene eseguito un nuovo tentativo di tutte le operazioni idempotenti e delle operazioni idempotenti condizionali solo se la condizione viene soddisfatta. I tentativi di eseguire operazioni non idempotenti non vengono ripetuti. Consulta la sezione Personalizzare i tentativi per esempi su come modificare il comportamento predefinito dei tentativi.

API REST

Quando chiami direttamente l'API JSON o XML, devi utilizzare l'algoritmo di backoff esponenziale per implementare la tua strategia di ripetizione.

Personalizzazione dei nuovi tentativi

Console

Non puoi personalizzare il comportamento dei nuovi tentativi utilizzando la console Google Cloud .

Riga di comando

Per i comandi gcloud storage, puoi controllare la strategia di ripetizione creando una configurazione denominata e impostando alcune o tutte le seguenti proprietà:

Impostazione Valore predefinito (in secondi)
base_retry_delay 1
exponential_sleep_multiplier 2
max_retries 32
max_retry_delay 32

Poi applichi la configurazione definita per ogni comando utilizzando il flag a livello di progetto --configuration o per tutti i comandi di Google Cloud CLI utilizzando il comando gcloud config set.

Librerie client

C++

Per personalizzare il comportamento di ripetizione, fornisci i valori per le seguenti opzioni quando inizializzi l'oggetto google::cloud::storage::Client:

  • google::cloud::storage::RetryPolicyOption: la libreria fornisce le classi google::cloud::storage::LimitedErrorCountRetryPolicy e google::cloud::storage::LimitedTimeRetryPolicy. Puoi fornire la tua classe, che deve implementare l'interfaccia google::cloud::RetryPolicy.

  • google::cloud::storage::BackoffPolicyOption: la libreria fornisce la classe google::cloud::storage::ExponentialBackoffPolicy. Puoi fornire la tua classe, che deve implementare l'interfaccia google::cloud::storage::BackoffPolicy.

  • google::cloud::storage::IdempotencyPolicyOption: la libreria fornisce le classi google::cloud::storage::StrictIdempotencyPolicy e google::cloud::storage::AlwaysRetryIdempotencyPolicy. Puoi fornire la tua classe, che deve implementare l'interfaccia google::cloud::storage::IdempotencyPolicy.

Per saperne di più, consulta la documentazione di riferimento della libreria client C++.

namespace gcs = ::google::cloud::storage;
// Create the client configuration:
auto options = google::cloud::Options{};
// Retries only idempotent operations.
options.set<gcs::IdempotencyPolicyOption>(
    gcs::StrictIdempotencyPolicy().clone());
// On error, it backs off for a random delay between [1, 3] seconds, then [3,
// 9] seconds, then [9, 27] seconds, etc. The backoff time never grows larger
// than 1 minute.
options.set<gcs::BackoffPolicyOption>(
    gcs::ExponentialBackoffPolicy(
        /*initial_delay=*/std::chrono::seconds(1),
        /*maximum_delay=*/std::chrono::minutes(1),
        /*scaling=*/3.0)
        .clone());
// Retries all operations for up to 5 minutes, including any backoff time.
options.set<gcs::RetryPolicyOption>(
    gcs::LimitedTimeRetryPolicy(std::chrono::minutes(5)).clone());
return gcs::Client(std::move(options));

C#

Non puoi personalizzare la strategia di ripetizione predefinita utilizzata dalla libreria client C#.

Vai

Quando inizializzi un client di archiviazione, viene impostata una configurazione di nuovi tentativi predefinita. Se non vengono sostituite, le opzioni nella configurazione vengono impostate sui valori predefiniti. Gli utenti possono configurare il comportamento di ripetizione non predefinito per una singola chiamata di libreria (utilizzando BucketHandle.Retryer e ObjectHandle.Retryer) o per tutte le chiamate effettuate da un client (utilizzando Client.SetRetry). Per modificare il comportamento dei nuovi tentativi, passa le RetryOptions pertinenti a uno di questi metodi.

Consulta il seguente esempio di codice per scoprire come personalizzare il comportamento dei tentativi.

import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/storage"
	"github.com/googleapis/gax-go/v2"
)

// configureRetries configures a custom retry strategy for a single API call.
func configureRetries(w io.Writer, bucket, object string) error {
	// bucket := "bucket-name"
	// object := "object-name"
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("storage.NewClient: %w", err)
	}
	defer client.Close()

	// Configure retries for all operations using this ObjectHandle. Retries may
	// also be configured on the BucketHandle or Client types.
	o := client.Bucket(bucket).Object(object).Retryer(
		// Use WithBackoff to control the timing of the exponential backoff.
		storage.WithBackoff(gax.Backoff{
			// Set the initial retry delay to a maximum of 2 seconds. The length of
			// pauses between retries is subject to random jitter.
			Initial: 2 * time.Second,
			// Set the maximum retry delay to 60 seconds.
			Max: 60 * time.Second,
			// Set the backoff multiplier to 3.0.
			Multiplier: 3,
		}),
		// Use WithPolicy to customize retry so that all requests are retried even
		// if they are non-idempotent.
		storage.WithPolicy(storage.RetryAlways),
	)

	// Use context timeouts to set an overall deadline on the call, including all
	// potential retries.
	ctx, cancel := context.WithTimeout(ctx, 500*time.Second)
	defer cancel()

	// Delete an object using the specified retry policy.
	if err := o.Delete(ctx); err != nil {
		return fmt.Errorf("Object(%q).Delete: %w", object, err)
	}
	fmt.Fprintf(w, "Blob %v deleted with a customized retry strategy.\n", object)
	return nil
}

Java

Quando inizializzi Storage, viene inizializzata anche un'istanza di RetrySettings. Se non vengono eseguite sostituzioni, le opzioni in RetrySettings sono impostate sui valori predefiniti. Per modificare il comportamento predefinito di ripetizione automatica, passa il StorageRetryStrategy personalizzato nel StorageOptions utilizzato per costruire l'istanza Storage. Per modificare uno degli altri parametri scalari, passa un RetrySettings personalizzato nel StorageOptions utilizzato per creare l'istanza Storage.

Consulta l'esempio seguente per scoprire come personalizzare il comportamento dei nuovi tentativi:


import com.google.api.gax.retrying.RetrySettings;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.google.cloud.storage.StorageRetryStrategy;
import org.threeten.bp.Duration;

public final class ConfigureRetries {
  public static void main(String[] args) {
    String bucketName = "my-bucket";
    String blobName = "blob/to/delete";
    deleteBlob(bucketName, blobName);
  }

  static void deleteBlob(String bucketName, String blobName) {
    // Customize retry behavior
    RetrySettings retrySettings =
        StorageOptions.getDefaultRetrySettings().toBuilder()
            // Set the max number of attempts to 10 (initial attempt plus 9 retries)
            .setMaxAttempts(10)
            // Set the backoff multiplier to 3.0
            .setRetryDelayMultiplier(3.0)
            // Set the max duration of all attempts to 5 minutes
            .setTotalTimeout(Duration.ofMinutes(5))
            .build();

    StorageOptions alwaysRetryStorageOptions =
        StorageOptions.newBuilder()
            // Customize retry so all requests are retried even if they are non-idempotent.
            .setStorageRetryStrategy(StorageRetryStrategy.getUniformStorageRetryStrategy())
            // provide the previously configured retrySettings
            .setRetrySettings(retrySettings)
            .build();

    // Instantiate a client
    Storage storage = alwaysRetryStorageOptions.getService();

    // Delete the blob
    BlobId blobId = BlobId.of(bucketName, blobName);
    boolean success = storage.delete(blobId);

    System.out.printf(
        "Deletion of Blob %s completed %s.%n", blobId, success ? "successfully" : "unsuccessfully");
  }
}

Node.js

Quando inizializzi Cloud Storage, viene inizializzato anche un file di configurazione retryOptions. A meno che non vengano sottoposte a override, le opzioni nella configurazione sono impostate sui valori predefiniti. Per modificare il comportamento di ripetizione predefinito, passa la configurazione di ripetizione personalizzata retryOptions al costruttore di archiviazione al momento dell'inizializzazione. La libreria client Node.js può utilizzare automaticamente le strategie di backoff per riprovare le richieste con il parametro autoRetry.

Consulta il seguente esempio di codice per scoprire come personalizzare il comportamento dei nuovi tentativi.

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';

// The ID of your GCS file
// const fileName = 'your-file-name';

// Imports the Google Cloud client library
const {Storage} = require('@google-cloud/storage');

// Creates a client
const storage = new Storage({
  retryOptions: {
    // If this is false, requests will not retry and the parameters
    // below will not affect retry behavior.
    autoRetry: true,
    // The multiplier by which to increase the delay time between the
    // completion of failed requests, and the initiation of the subsequent
    // retrying request.
    retryDelayMultiplier: 3,
    // The total time between an initial request getting sent and its timeout.
    // After timeout, an error will be returned regardless of any retry attempts
    // made during this time period.
    totalTimeout: 500,
    // The maximum delay time between requests. When this value is reached,
    // retryDelayMultiplier will no longer be used to increase delay time.
    maxRetryDelay: 60,
    // The maximum number of automatic retries attempted before returning
    // the error.
    maxRetries: 5,
    // Will respect other retry settings and attempt to always retry
    // conditionally idempotent operations, regardless of precondition
    idempotencyStrategy: IdempotencyStrategy.RetryAlways,
  },
});
console.log(
  'Functions are customized to be retried according to the following parameters:'
);
console.log(`Auto Retry: ${storage.retryOptions.autoRetry}`);
console.log(
  `Retry delay multiplier: ${storage.retryOptions.retryDelayMultiplier}`
);
console.log(`Total timeout: ${storage.retryOptions.totalTimeout}`);
console.log(`Maximum retry delay: ${storage.retryOptions.maxRetryDelay}`);
console.log(`Maximum retries: ${storage.retryOptions.maxRetries}`);
console.log(
  `Idempotency strategy: ${storage.retryOptions.idempotencyStrategy}`
);

async function deleteFileWithCustomizedRetrySetting() {
  await storage.bucket(bucketName).file(fileName).delete();
  console.log(`File ${fileName} deleted with a customized retry strategy.`);
}

deleteFileWithCustomizedRetrySetting();

PHP

Quando inizializzi un client di archiviazione, viene impostata una configurazione di ripetizione predefinita. A meno che non vengano sottoposte a override, le opzioni nella configurazione sono impostate sui valori predefiniti. Gli utenti possono configurare un comportamento di ripetizione non predefinito per un client o una singola chiamata di operazione passando le opzioni di override in un array.

Consulta il seguente esempio di codice per scoprire come personalizzare il comportamento dei nuovi tentativi.

use Google\Cloud\Storage\StorageClient;

/**
 * Configures retries with customizations.
 *
 * @param string $bucketName The name of your Cloud Storage bucket.
 *        (e.g. 'my-bucket')
 */
function configure_retries(string $bucketName): void
{
    $storage = new StorageClient([
        // The maximum number of automatic retries attempted before returning
        // the error.
        // Default: 3
        'retries' => 10,

        // Exponential backoff settings
        // Retry strategy to signify that we never want to retry an operation
        // even if the error is retryable.
        // Default: StorageClient::RETRY_IDEMPOTENT
        'retryStrategy' => StorageClient::RETRY_ALWAYS,

        // Executes a delay
        // Defaults to utilizing `usleep`.
        // Function signature should match: `function (int $delay) : void`.
        // This function is mostly used internally, so the tests don't wait
        // the time of the delay to run.
        'restDelayFunction' => function ($delay) {
            usleep($delay);
        },

        // Sets the conditions for determining how long to wait between attempts to retry.
        // Function signature should match: `function (int $attempt) : int`.
        // Allows to change the initial retry delay, retry delay multiplier and maximum retry delay.
        'restCalcDelayFunction' => fn ($attempt) => ($attempt + 1) * 100,

        // Sets the conditions for whether or not a request should attempt to retry.
        // Function signature should match: `function (\Exception $ex) : bool`.
        'restRetryFunction' => function (\Exception $e) {
            // Custom logic: ex. only retry if the error code is 404.
            return $e->getCode() === 404;
        },

        // Runs after the restRetryFunction. This might be used to simply consume the
        // exception and $arguments b/w retries. This returns the new $arguments thus allowing
        // modification on demand for $arguments. For ex: changing the headers in b/w retries.
        'restRetryListener' => function (\Exception $e, $retryAttempt, &$arguments) {
            // logic
        },
    ]);
    $bucket = $storage->bucket($bucketName);
    $operationRetriesOverrides = [
        // The maximum number of automatic retries attempted before returning
        // the error.
        // Default: 3
        'retries' => 10,

        // Exponential backoff settings
        // Retry strategy to signify that we never want to retry an operation
        // even if the error is retryable.
        // Default: StorageClient::RETRY_IDEMPOTENT
        'retryStrategy' => StorageClient::RETRY_ALWAYS,

        // Executes a delay
        // Defaults to utilizing `usleep`.
        // Function signature should match: `function (int $delay) : void`.
        // This function is mostly used internally, so the tests don't wait
        // the time of the delay to run.
        'restDelayFunction' => function ($delay) {
            usleep($delay);
        },

        // Sets the conditions for determining how long to wait between attempts to retry.
        // Function signature should match: `function (int $attempt) : int`.
        // Allows to change the initial retry delay, retry delay multiplier and maximum retry delay.
        'restCalcDelayFunction' => fn ($attempt) => ($attempt + 1) * 100,

        // Sets the conditions for whether or not a request should attempt to retry.
        // Function signature should match: `function (\Exception $ex) : bool`.
        'restRetryFunction' => function (\Exception $e) {
            // Custom logic: ex. only retry if the error code is 404.
            return $e->getCode() === 404;
        },

        // Runs after the restRetryFunction. This might be used to simply consume the
        // exception and $arguments b/w retries. This returns the new $arguments thus allowing
        // modification on demand for $arguments. For ex: changing the headers in b/w retries.
        'restRetryListener' => function (\Exception $e, $retryAttempt, &$arguments) {
            // logic
        },
    ];
    foreach ($bucket->objects($operationRetriesOverrides) as $object) {
        printf('Object: %s' . PHP_EOL, $object->name());
    }
}

Python

Per modificare il comportamento dei tentativi predefinito, crea una copia dell'oggetto google.cloud.storage.retry.DEFAULT_RETRY chiamandolo con un metodo with_BEHAVIOR. La libreria client Python utilizza automaticamente le strategie di backoff per riprovare le richieste se includi il parametro DEFAULT_RETRY.

Tieni presente che with_predicate non è supportato per le operazioni che recuperano o inviano dati di payload agli oggetti, come caricamenti e download. Ti consigliamo di modificare gli attributi uno alla volta. Per saperne di più, consulta la documentazione di riferimento per i nuovi tentativi di google-api-core.

Per configurare un nuovo tentativo condizionale, crea un oggetto ConditionalRetryPolicy e racchiudi l'oggetto Retry personalizzato con DEFAULT_RETRY_IF_GENERATION_SPECIFIED, DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED o DEFAULT_RETRY_IF_ETAG_IN_JSON.

Consulta il seguente esempio di codice per scoprire come personalizzare il comportamento dei tentativi.

from google.cloud import storage
from google.cloud.storage.retry import DEFAULT_RETRY


def configure_retries(bucket_name, blob_name):
    """Configures retries with customizations."""
    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"
    # The ID of your GCS object
    # blob_name = "your-object-name"

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(blob_name)

    # Customize retry with a timeout of 500 seconds (default=120 seconds).
    modified_retry = DEFAULT_RETRY.with_timeout(500.0)
    # Customize retry with an initial wait time of 1.5 (default=1.0).
    # Customize retry with a wait time multiplier per iteration of 1.2 (default=2.0).
    # Customize retry with a maximum wait time of 45.0 (default=60.0).
    modified_retry = modified_retry.with_delay(initial=1.5, multiplier=1.2, maximum=45.0)

    # blob.delete() uses DEFAULT_RETRY by default.
    # Pass in modified_retry to override the default retry behavior.
    print(
        f"The following library method is customized to be retried according to the following configurations: {modified_retry}"
    )

    blob.delete(retry=modified_retry)
    print(f"Blob {blob_name} deleted with a customized retry strategy.")

Ruby

Quando inizializzi il client di archiviazione, tutte le configurazioni dei tentativi vengono impostate sui valori mostrati nella tabella precedente. Per modificare il comportamento predefinito dei tentativi, trasmetti le configurazioni dei tentativi durante l'inizializzazione del client di archiviazione.

Per ignorare il numero di tentativi per una determinata operazione, passa retries nel parametro options dell'operazione.

def configure_retries bucket_name: nil, file_name: nil
  # The ID of your GCS bucket
  # bucket_name = "your-unique-bucket-name"

  # The ID of your GCS object
  # file_name = "your-file-name"

  require "google/cloud/storage"

  # Creates a client
  storage = Google::Cloud::Storage.new(

    # The maximum number of automatic retries attempted before returning
    # the error.
    #
    # Customize retry configuration with the maximum retry attempt of 5.
    retries: 5,

    # The total time in seconds that requests are allowed to keep being retried.
    # After max_elapsed_time, an error will be returned regardless of any
    # retry attempts made during this time period.
    #
    # Customize retry configuration with maximum elapsed time of 500 seconds.
    max_elapsed_time: 500,

    # The initial interval between the completion of failed requests, and the
    # initiation of the subsequent retrying request.
    #
    # Customize retry configuration with an initial interval of 1.5 seconds.
    base_interval: 1.5,

    # The maximum interval between requests. When this value is reached,
    # multiplier will no longer be used to increase the interval.
    #
    # Customize retry configuration with maximum interval of 45.0 seconds.
    max_interval: 45,

    # The multiplier by which to increase the interval between the completion
    # of failed requests, and the initiation of the subsequent retrying request.
    #
    # Customize retry configuration with an interval multiplier per iteration of 1.2.
    multiplier: 1.2
  )

  # Uses the retry configuration set during the client initialization above with 5 retries
  file = storage.service.get_file bucket_name, file_name

  # Maximum retry attempt can be overridden for each operation using options parameter.
  storage.service.delete_file bucket_name, file_name, options: { retries: 4 }
  puts "File #{file.name} deleted with a customized retry strategy."
end

API REST

Utilizza l'algoritmo di backoff esponenziale per implementare la tua strategia di ripetizione dei tentativi.

Algoritmo di backoff esponenziale

Un algoritmo di backoff esponenziale riprova le richieste utilizzando tempi di attesa tra le richieste che aumentano in modo esponenziale, fino a un tempo di backoff massimo. In genere, devi utilizzare il backoff esponenziale con jitter per riprovare le richieste che soddisfano i criteri di risposta e di idempotenza. Per le best practice sull'implementazione dei tentativi automatici con backoff esponenziale, consulta Risoluzione degli errori a cascata.

Anti-pattern di ripetizione dei tentativi

Ti consigliamo di utilizzare o personalizzare i meccanismi di ripetizione integrati, se applicabili. Consulta Personalizzazione dei tentativi di ripetizione. Che tu stia utilizzando i meccanismi di ripetizione predefiniti, li stia personalizzando o stia implementando una tua logica di ripetizione, è fondamentale evitare i seguenti anti-pattern comuni, in quanto possono esacerbare i problemi anziché risolverli.

Nuovo tentativo senza backoff

La ripetizione immediata delle richieste o con ritardi molto brevi può portare a errori a cascata, ovvero errori che potrebbero attivarne altri.

Come evitare questo problema: implementa il backoff esponenziale con jitter. Questa strategia aumenta progressivamente il tempo di attesa tra i tentativi e aggiunge un elemento casuale per evitare che i tentativi sovraccarichino il servizio.

Riprovare in modo incondizionato le operazioni non idempotenti

L'esecuzione ripetuta di operazioni non idempotenti può portare a effetti collaterali indesiderati, come sovrascritture o eliminazioni involontarie di dati.

Come evitare questo problema: comprendi a fondo le caratteristiche di idempotenza di ogni operazione, come descritto nella sezione Idempotenza delle operazioni. Per le operazioni non idempotenti, assicurati che la logica di ripetizione possa gestire i potenziali duplicati o evitare di ripetere i tentativi. Fai attenzione con i nuovi tentativi che potrebbero portare a race condition.

Nuovo tentativo di invio di errori irreversibili

Considerare tutti gli errori come riprovabili può essere problematico. Alcuni errori, ad esempio errori di autorizzazione o richieste non valide, sono persistenti e riprovare senza risolvere la causa sottostante non avrà esito positivo e potrebbe comportare il blocco delle applicazioni in un loop infinito.

Come evitare questo problema: classifica gli errori in temporanei (ripetibili) e permanenti (non ripetibili). Riprova solo in caso di errori temporanei, come i codici HTTP 408, 429 e 5xx, o problemi di connessione specifici. Per gli errori permanenti, registrali e gestisci la causa sottostante in modo appropriato.

Ignorare i limiti di nuovi tentativi

Se i tentativi vengono ripetuti all'infinito, l'applicazione potrebbe esaurire le risorse o inviare continuamente richieste a un servizio che non si ripristinerà senza intervento.

Come evitare questo problema: personalizza i limiti di nuovi tentativi in base alla natura del tuo workload. Per i workload sensibili alla latenza, valuta la possibilità di impostare una durata massima totale dei nuovi tentativi per garantire una risposta o un errore tempestivi. Per i workload batch, che potrebbero tollerare periodi di nuovi tentativi più lunghi per errori temporanei lato server, valuta la possibilità di impostare un limite totale di nuovi tentativi più elevato.

Livelli di nuovi tentativi non necessari

L'aggiunta di una logica di ripetizione personalizzata a livello di applicazione oltre ai meccanismi di ripetizione esistenti può portare a un numero eccessivo di tentativi di ripetizione. Ad esempio, se la tua applicazione ritenta un'operazione tre volte e la libreria client sottostante la ritenta tre volte per ogni tentativo dell'applicazione, potresti ritrovarti con nove tentativi. L'invio di un numero elevato di nuovi tentativi per errori che non possono essere ripetuti potrebbe causare la limitazione delle richieste, limitando il throughput di tutti i workload. Un numero elevato di nuovi tentativi potrebbe anche aumentare la latenza delle richieste senza migliorare il tasso di successo.

Come evitare questo problema: ti consigliamo di utilizzare e configurare i meccanismi di ripetizione integrati. Se devi implementare i tentativi a livello di applicazione, ad esempio per una logica di business specifica che si estende su più operazioni, fallo con una chiara comprensione del comportamento dei tentativi sottostante. Valuta la possibilità di disattivare o limitare in modo significativo i nuovi tentativi in uno dei livelli per evitare effetti moltiplicativi.

Passaggi successivi