Обработка ошибок в пакете SDK Azure для C++

Обработка ошибок в пакете SDK Azure для C++ в основном реализуется с помощью исключений C++. Этот подход соответствует стандартным методикам C++ и обеспечивает ясное сообщение об ошибках и их обработку в SDK. Когда приложение C++ взаимодействует со службами Azure, операции могут завершиться сбоем по различным причинам, таким как проблемы с проверкой подлинности, недоступность службы, недопустимые запросы или ограничения ресурсов. Пакет SDK записывает эти ошибки в виде исключений, которые предоставляют подробные сведения о сбое.

Иерархия исключений

Основные типы исключений

Пакет SDK Azure для C++ использует иерархию классов исключений, при этом наиболее важные из них:

  1. std::runtime_error — базовое стандартное исключение C++, от которого наследуются исключения, относящиеся к Azure.

  2. Azure::Core::RequestFailedException — производное от std::runtime_error, это базовое исключение для всех сбоев запросов службы Azure. azure/core/exception.hppЭто исключение возникает при сбое запроса к службе Azure. Он предоставляет:

    • Код состояния HTTP
    • Коды ошибок из службы
    • Сообщения об ошибках
    • Запрос идентификаторов для устранения неполадок
    • Необработанный HTTP-ответ
  3. Azure::Core::OperationCancelledException — Производное от std::runtime_error, это исключение возникает при отмене операции, обычно через объект контекста.

  4. Azure::Core::Http::TransportException — Производное от Azure::Core::RequestFailedExceptionэтого исключения возникает при возникновении ошибки в транспортном слое HTTP, например сбоях подключения.

  5. Azure::Core::Credentials::AuthenticationException — Происходящее от std::exception, это исключение бросается при сбое проверки подлинности со службами Azure.

Типы исключений для конкретной службы

Различные службы Azure расширяют базовые типы исключений для предоставления сведений об ошибках для конкретной службы:

  1. Azure::Storage::StorageException — расширяет RequestFailedException, добавляя дополнительную информацию, специфичную для хранения. Это исключение включает:

    • Коды ошибок для конкретного хранилища
    • Дополнительные сведения в тексте ответа
    • Сведения о неудачной операции хранения
  2. Azure::Messaging::EventHubs::EventHubsException — исключение, конкретное для операций Центров событий. Сюда входят:

    • Условие ошибки (символическое значение AMQP (Расширенный Протокол Очереди Сообщений))
    • Описание ошибки
    • Код состояния
    • Сведения о том, является ли ошибка временной

Сведения об ошибках в исключениях

Класс RequestFailedException содержит подробные сведения о сбоях службы:

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

Исключения, относящиеся к службе, могут добавлять дополнительные поля. Например, StorageException добавляет 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 ... */
};

Шаблоны обработки исключений и примеры

Использование кодов ошибок

Исключения служб содержат ErrorCode значения, которые можно использовать для принятия решений о том, как обрабатывать сбои. Ниже приведен пример со службами хранилища:

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

Обработка основных исключений

Базовый шаблон обработки исключений в пакете 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
}

Обработка временных ошибок

Некоторые службы, такие как Центры событий, предоставляют сведения о том, является ли ошибка временной, что позволяет реализовать логику повторных попыток.

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

Пакет SDK реализует внутренние политики повторных попыток для временных сбоев, но вы хотите обрабатывать конкретные случаи в коде приложения.

Обработка ошибок для конкретной службы

Для служб хранения (Блоб, файлы, очереди и т. д.) вы можете управлять обработкой ошибок, основываясь на кодах ошибок и 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;
    }
}

Для операций Key Vault может потребоваться отдельно обрабатывать исключения проверки подлинности:

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
}

Рекомендации по безопасности потоков

Пакет SDK Azure для C++ гарантирует, что методы экземпляра клиента являются потокобезопасны и не зависят друг от друга. Это означает, что можно безопасно использовать экземпляр клиента в нескольких потоках без синхронизации.

При обработке исключений между потоками следует учитывать:

  1. Объекты исключений не должны совместно использоваться между потоками, если не правильно синхронизированы
  2. В RequestFailedException входит конструктор копирования, создающий глубокую копию, который может использоваться при необходимости передачи сведений об исключении между потоками.