Control de errores en el SDK de Azure para C++

El control de errores en el SDK de Azure para C++ se implementa principalmente a través de excepciones de C++. Este enfoque se alinea con las prácticas estándar de C++ y permite informes claros de errores y gestión en todo el SDK. Cuando la aplicación de C++ interactúa con los servicios de Azure, las operaciones pueden producir errores por diversos motivos, como problemas de autenticación, falta de disponibilidad del servicio, solicitudes no válidas o restricciones de recursos. El SDK captura estos errores como excepciones que proporcionan información detallada sobre el error.

Jerarquía de excepciones

Tipos de excepciones principales

El SDK de Azure para C++ usa una jerarquía de clases de excepción, siendo las más importantes:

  1. std::runtime_error : excepción estándar de C++ base de la que heredan las excepciones específicas de Azure.

  2. Azure::Core::RequestFailedException - Derivado de std::runtime_error, esta es la excepción base para todos los errores de solicitud de servicio de Azure. Se define en azure/core/exception.hpp, esta excepción se produce cuando se produce un error en una solicitud a un servicio de Azure. Proporciona:

    • Código de estado HTTP
    • Códigos de error del servicio
    • Mensajes de error
    • ID de solicitud para la resolución de problemas
    • La respuesta HTTP sin procesar
  3. Azure::Core::OperationCancelledException : se deriva de std::runtime_error, esta excepción se produce cuando se cancela una operación, normalmente a través de un objeto de contexto.

  4. Azure::Core::Http::TransportException : se deriva de Azure::Core::RequestFailedException, esta excepción se produce cuando se produce un error en la capa de transporte HTTP, como errores de conexión.

  5. Azure::Core::Credentials::AuthenticationException : se deriva de std::exception, esta excepción se produce cuando se produce un error en la autenticación con los servicios de Azure.

Tipos de excepciones específicos del servicio

Los distintos servicios de Azure amplían los tipos de excepción base para proporcionar información de error específica del servicio:

  1. Azure::Storage::StorageException - Amplía RequestFailedException con información adicional específica del almacenamiento. Esta excepción incluye:

    • Códigos de error específicos del almacenamiento
    • Información adicional incluida en el cuerpo de la respuesta
    • Detalles sobre la operación de almacenamiento fallida
  2. Azure::Messaging::EventHubs::EventHubsException : una excepción específica de las operaciones de Event Hubs. Incluye:

    • Condición de error (un valor simbólico del protocolo Advanced Message Queuing (AMQP))
    • Descripción del error
    • Código de estado
    • Información sobre si el error es transitorio

Información de error en las excepciones

La RequestFailedException clase contiene información enriquecida sobre los errores de servicio:

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

Las excepciones específicas del servicio pueden agregar campos adicionales. Por ejemplo, StorageException agrega 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 ... */
};

Ejemplos y patrones de control de excepciones

Uso de códigos de error

Las excepciones de servicio contienen ErrorCode valores que se pueden usar para tomar decisiones sobre cómo controlar los errores. Este es un ejemplo de servicios de almacenamiento:

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

Control de excepciones básicas

Patrón básico para controlar excepciones en el SDK de 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
}

Control de errores transitorios

Algunos servicios, como Event Hubs, proporcionan información sobre si un error es transitorio, lo que permite la lógica de reintento:

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

El SDK implementa directivas de reintento internas para errores transitorios, pero es posible que quiera controlar casos específicos en el código de la aplicación.

Control de errores específicos del servicio

Para servicios de almacenamiento como Blobs, Archivos y Colas, puede gestionar los errores basándose tanto en los códigos de error como en los códigos de estado 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;
    }
}

En el caso de las operaciones de Key Vault, es posible que tenga que controlar las excepciones de autenticación por separado:

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
}

Consideraciones de seguridad en el manejo de hilos

El SDK de Azure para C++ garantiza que los métodos de instancia del cliente sean seguros para subprocesos e independientes entre sí. Esto significa que puede usar de forma segura una instancia de cliente en varios subprocesos sin sincronización.

Al controlar excepciones entre subprocesos, tenga en cuenta lo siguiente:

  1. Los objetos de excepción no se deben compartir entre subprocesos a menos que se sincronicen correctamente.
  2. RequestFailedException incluye un constructor de copia que crea una copia profunda, que se puede usar al necesitar pasar información de excepciones entre subprocesos.