Gestione degli errori in Azure SDK per C++

La gestione degli errori in Azure SDK per C++ viene implementata principalmente tramite eccezioni C++. Questo approccio è allineato alle procedure C++ standard e consente la chiara segnalazione degli errori e la gestione nell'SDK. Quando l'applicazione C++ interagisce con i servizi di Azure, le operazioni possono avere esito negativo per diversi motivi, ad esempio problemi di autenticazione, mancata disponibilità del servizio, richieste non valide o vincoli di risorse. L'SDK acquisisce questi errori come eccezioni che forniscono informazioni dettagliate sull'errore.

Gerarchia delle eccezioni

Tipi di eccezione principali

Azure SDK per C++ usa una gerarchia di classi di eccezioni, con quelle più importanti:

  1. std::runtime_error - Eccezione standard C++ di base da cui ereditano le eccezioni specifiche di Azure.

  2. Azure::Core::RequestFailedException - Derivato da std::runtime_error, si tratta dell'eccezione di base per tutti gli errori di richiesta del servizio di Azure. Definita in azure/core/exception.hpp, questa eccezione viene generata quando una richiesta a un servizio di Azure non riesce. Offre:

    • Codice di stato HTTP
    • Codici di errore del servizio
    • Messaggi di errore
    • ID di richiesta per la risoluzione dei problemi
    • Risposta HTTP non elaborata
  3. Azure::Core::OperationCancelledException - Derivata da std::runtime_error, questa eccezione viene generata quando un'operazione viene annullata, in genere tramite un oggetto contesto.

  4. Azure::Core::Http::TransportException - Derivata da Azure::Core::RequestFailedException, questa eccezione viene generata quando si verifica un errore nel livello di trasporto HTTP, ad esempio errori di connessione.

  5. Azure::Core::Credentials::AuthenticationException - Derivata da std::exception, questa eccezione viene generata quando l'autenticazione con i servizi di Azure non riesce.

Tipi di eccezione specifici del servizio

Diversi servizi di Azure estendono i tipi di eccezione di base per fornire informazioni sugli errori specifiche del servizio:

  1. Azure::Storage::StorageException - Estende RequestFailedException con altre informazioni specifiche sull'archiviazione. Questa eccezione include:

    • Codici di errore specifici dell'archiviazione
    • Informazioni aggiuntive nel corpo della risposta
    • Dettagli sull'operazione di archiviazione non riuscita
  2. Azure::Messaging::EventHubs::EventHubsException - Eccezione specifica per le operazioni di Hub eventi. Comprende:

    • Condizione di errore (valore simbolico del protocollo AMQP (Advanced Message Queuing Protocol)
    • La descrizione dell'errore
    • Codice di stato
    • Informazioni su se l'errore è temporaneo

Informazioni sugli errori nelle eccezioni

La RequestFailedException classe contiene informazioni dettagliate sugli errori del servizio:

class RequestFailedException : public std::runtime_error {
public:
    // The entire HTTP raw response
    std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
    
    // The HTTP response code
    Azure::Core::Http::HttpStatusCode StatusCode;
    
    // The HTTP reason phrase from the response
    std::string ReasonPhrase;
    
    // The client request header (x-ms-client-request-id) from the HTTP response
    std::string ClientRequestId;
    
    // The request ID header (x-ms-request-id) from the HTTP response
    std::string RequestId;
    
    // The error code from service returned in the HTTP response
    std::string ErrorCode;
    
    // The error message from the service returned in the HTTP response
    std::string Message;
    
    /* ... constructors and other methods ... */
};

Le eccezioni specifiche del servizio possono aggiungere campi aggiuntivi. Ad esempio, StorageException aggiunge AdditionalInformation:

struct StorageException final : public Azure::Core::RequestFailedException {
    // Some storage-specific information in response body
    std::map<std::string, std::string> AdditionalInformation;
    
    /* ... constructors and other methods ... */
};

Modelli ed esempi di gestione delle eccezioni

Uso dei codici di errore

Le eccezioni del servizio contengono ErrorCode valori che possono essere usati per prendere decisioni su come gestire gli errori. Ecco un esempio con i servizi di archiviazione:

try {
    containerClient.Delete();
}
catch (Azure::Storage::StorageException& e) {
    if (e.ErrorCode == "ContainerNotFound") {
        // Ignore the error if the container does not exist
    }
    else {
        // Handle other errors here
    }
}

Gestione delle eccezioni di base

Modello di base per la gestione delle eccezioni in Azure SDK:

try {
    // Perform an Azure SDK operation
    result = client.SomeOperation();
}
catch (Azure::Core::RequestFailedException const& e) {
    std::cout << "Request Failed Exception happened:" << std::endl << e.what() << std::endl;
    if (e.RawResponse) {
        std::cout << "Error Code: " << e.ErrorCode << std::endl;
        std::cout << "Error Message: " << e.Message << std::endl;
    }
    // Handle or rethrow as appropriate
}
catch (std::exception const& e) {
    std::cout << "Other exception: " << e.what() << std::endl;
    // Handle general exceptions
}

Gestione degli errori temporanei

Alcuni servizi, ad esempio Hub eventi, forniscono informazioni sul fatto che un errore sia temporaneo, consentendo la logica di ripetizione dei tentativi:

try {
    // EventHubs operation
}
catch (Azure::Messaging::EventHubs::EventHubsException& e) {
    if (e.IsTransient) {
        // Retry the operation after a delay
    }
    else {
        // Handle permanent failure
    }
}

L'SDK implementa criteri di ripetizione dei tentativi interni per gli errori temporanei, ma potrebbe comunque essere necessario gestire casi specifici nel codice dell'applicazione.

Gestione degli errori specifici del servizio

Per i servizi di archiviazione come Blobs, File e Code, è possibile gestire gli errori in base sia ai codici di errore sia ai codici di stato HTTP:

try {
    shareClient.Delete();
}
catch (Azure::Storage::StorageException& e) {
    if (e.ErrorCode == "ShareNotFound") {
        // Ignore the error if the file share does not exist
    }
    else if (e.StatusCode == Azure::Core::Http::HttpStatusCode::Conflict) {
        // Handle conflict error (e.g., resource in use)
        std::cout << "Conflict error: " << e.Message << std::endl;
        
        // Check additional information
        for (auto const& info : e.AdditionalInformation) {
            std::cout << info.first << ": " << info.second << std::endl;
        }
    }
    else {
        // Handle other errors based on status code or error code
        std::cout << "Error: " << e.Message << " (Code: " << e.ErrorCode << ")" << std::endl;
    }
}

Per le operazioni di Key Vault, potrebbe essere necessario gestire separatamente le eccezioni di autenticazione:

try {
    // Key Vault operation
}
catch (Azure::Core::Credentials::AuthenticationException const& e) {
    std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
    // Handle authentication failure (e.g., invalid credentials)
}
catch (Azure::Core::RequestFailedException const& e) {
    std::cout << "Key Vault Client Exception happened:" << std::endl << e.Message << std::endl;
    // Handle Key Vault specific errors
}

Considerazioni sulla sicurezza dei thread

Azure SDK per C++ garantisce che i metodi di istanza client siano thread-safe e indipendenti l'uno dall'altro. Ciò significa che è possibile usare in modo sicuro un'istanza client tra più thread senza sincronizzazione.

Quando si gestiscono le eccezioni tra i thread, tenere presente quanto segue:

  1. Gli oggetti eccezione non devono essere condivisi tra thread, a meno che non siano sincronizzati correttamente
  2. RequestFailedException include un costruttore di copia che crea una copia completa, che può essere usata quando è necessario passare le informazioni sulle eccezioni tra thread