Gestion des erreurs dans le Kit de développement logiciel (SDK) Azure pour C++

La gestion des erreurs dans le Kit de développement logiciel (SDK) Azure pour C++ est principalement implémentée via des exceptions C++. Cette approche s’aligne sur les pratiques C++ standard et permet de signaler et de gérer clairement les erreurs dans le SDK. Lorsque votre application C++ interagit avec les services Azure, les opérations peuvent échouer pour différentes raisons telles que les problèmes d’authentification, l’indisponibilité du service, les demandes non valides ou les contraintes de ressources. Le Kit de développement logiciel (SDK) capture ces erreurs en tant qu’exceptions qui fournissent des informations détaillées sur l’échec.

Hiérarchie d’exceptions

Types d’exceptions principaux

Le Kit de développement logiciel (SDK) Azure pour C++ utilise une hiérarchie de classes d’exception, les plus importantes étant :

  1. std::runtime_error - Exception standard C++ de base à partir de laquelle héritent des exceptions spécifiques à Azure.

  2. Azure::Core::RequestFailedException - Dérivé de std::runtime_error, il s’agit de l’exception de base pour tous les échecs de demande de service Azure. Définie dans azure/core/exception.hpp, cette exception est levée lorsqu’une demande adressée à un service Azure échoue. Il offre :

    • Code d’état HTTP
    • Codes d’erreur du service
    • Messages d’erreur
    • Identifiants de requête pour le dépannage
    • Réponse HTTP brute
  3. Azure::Core::OperationCancelledException - Dérivée de std::runtime_error, cette exception est levée lorsqu’une opération est annulée, généralement par le biais d’un objet de contexte.

  4. Azure::Core::Http::TransportException - Dérivée de Azure::Core::RequestFailedException, cette exception est levée lorsqu’il existe une erreur dans la couche de transport HTTP, comme les échecs de connexion.

  5. Azure::Core::Credentials::AuthenticationException - Dérivée de std::exception, cette exception est levée lorsque l’authentification avec les services Azure échoue.

Types d’exceptions spécifiques au service

Différents services Azure étendent les types d’exceptions de base pour fournir des informations d’erreur spécifiques au service :

  1. Azure::Storage::StorageException - Étend RequestFailedException avec d’autres informations spécifiques au stockage. Cette exception inclut :

    • Codes d’erreur spécifiques au stockage
    • Informations supplémentaires dans le corps de la réponse
    • Détails sur l’échec de l’opération de stockage
  2. Azure::Messaging::EventHubs::EventHubsException - Exception spécifique aux opérations Event Hubs. Il inclut :

    • Condition d’erreur (valeur symbolique d’AMQP (Advanced Message Queuing Protocol))
    • Description de l'erreur
    • Code de statut
    • Informations sur la question de savoir si l’erreur est temporaire

Informations d’erreur dans les exceptions

La RequestFailedException classe contient des informations complètes sur les échecs de service :

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 ... */
};

Les exceptions spécifiques au service peuvent ajouter des champs supplémentaires. Par exemple, StorageException ajoute 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 ... */
};

Modèles et exemples de gestion des exceptions

Utilisation des codes d’erreur

Les exceptions de service contiennent des ErrorCode valeurs qui peuvent être utilisées pour prendre des décisions sur la façon de gérer les défaillances. Voici un exemple avec les services de stockage :

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
    }
}

Gestion des exceptions de base

Modèle de base pour la gestion des exceptions dans le Kit de développement logiciel (SDK) Azure :

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
}

Gestion des erreurs temporaires

Certains services, comme Event Hubs, fournissent des informations sur la façon dont une erreur est temporaire, ce qui permet une logique de nouvelle tentative :

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

Le Kit de développement logiciel (SDK) implémente des stratégies de nouvelle tentative interne pour les échecs temporaires, mais vous souhaitez gérer des cas spécifiques dans votre code d’application.

Gestion des erreurs propres au service

Pour les services de stockage (objets blob, fichiers, files d’attente, etc.), vous pouvez gérer les erreurs en fonction des codes d’erreur et des codes d’état 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;
    }
}

Pour les opérations Key Vault, vous devrez peut-être gérer les exceptions d’authentification séparément :

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
}

Considérations relatives à la sécurité des threads

Le Kit de développement logiciel (SDK) Azure pour C++ garantit que les méthodes d’instance clientes sont thread-safe et indépendantes les unes des autres. Cela signifie que vous pouvez utiliser en toute sécurité une instance cliente sur plusieurs threads sans synchronisation.

Lors de la gestion des exceptions entre les threads, gardez à l’esprit :

  1. Les objets d’exception ne doivent pas être partagés entre les threads, sauf s’ils sont correctement synchronisés
  2. RequestFailedException inclut un constructeur de copie profonde qui crée une copie approfondie, pouvant être utilisé pour échanger des informations d'exception entre threads.