Obsługa błędów w zestawie Azure SDK dla języka C++

Obsługa błędów w zestawie Azure SDK dla języka C++ jest implementowana głównie za pomocą wyjątków języka C++. Takie podejście jest zgodne ze standardowymi praktykami języka C++ i umożliwia jasne raportowanie błędów i obsługę w zestawie SDK. Gdy aplikacja C++ współdziała z usługami platformy Azure, operacje mogą zakończyć się niepowodzeniem z różnych powodów, takich jak problemy z uwierzytelnianiem, niedostępność usługi, nieprawidłowe żądania lub ograniczenia zasobów. Zestaw SDK przechwytuje te błędy jako wyjątki, które zawierają szczegółowe informacje o awarii.

Hierarchia wyjątków

Podstawowe typy wyjątków

Zestaw Azure SDK dla języka C++ używa hierarchii klas wyjątków, z których najważniejsze są:

  1. std::runtime_error — podstawowy wyjątek standardowy C++, z którego dziedziczą wyjątki specyficzne dla platformy Azure.

  2. Azure::Core::RequestFailedException — Wywiedziony z std::runtime_error, jest to podstawowy wyjątek dla wszystkich niepowodzeń żądań usługi platformy Azure. Ten wyjątek, zdefiniowany w azure/core/exception.hpp, jest zgłaszany, gdy żądanie do usługi Azure kończy się niepowodzeniem. Zapewnia:

    • Kod stanu HTTP
    • Kody błędów z usługi
    • Komunikaty o błędach
    • Identyfikatory żądań do diagnostyki i rozwiązywania problemów
    • Nieprzetworzona odpowiedź HTTP
  3. Azure::Core::OperationCancelledException. Wynikający z std::runtime_error wyjątek jest zgłaszany, gdy operacja jest anulowana, zwykle za pośrednictwem obiektu kontekstu.

  4. Azure::Core::Http::TransportException — Ten Azure::Core::RequestFailedExceptionwyjątek jest zgłaszany w przypadku wystąpienia błędu w warstwie transportu HTTP, takiej jak błędy połączeń.

  5. Azure::Core::Credentials::AuthenticationException — Wywodzący się z std::exception, ten wyjątek jest zgłaszany w przypadku niepowodzenia uwierzytelniania z usługami platformy Azure.

Typy wyjątków specyficznych dla usługi

Różne usługi platformy Azure rozszerzają podstawowe typy wyjątków w celu dostarczania informacji o błędach specyficznych dla usługi:

  1. Azure::Storage::StorageException — Rozszerza RequestFailedException o inne informacje specyficzne dla magazynu. Ten wyjątek obejmuje:

    • Kody błędów specyficzne dla przechowywania
    • Dodatkowe informacje w treści odpowiedzi
    • Szczegółowe informacje o nieudanej operacji magazynowania
  2. Azure::Messaging::EventHubs::EventHubsException — Wyjątek specyficzny dla operacji usługi Event Hubs. Zawartość:

    • Warunek błędu (wartość symboliczna z protokołu AMQP (Advanced Message Queuing Protocol))
    • Opis błędu
    • Kod stanu
    • Informacje o tym, czy błąd jest przejściowy

Informacje o błędach w wyjątkach

Klasa RequestFailedException zawiera zaawansowane informacje o błędach usługi:

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

Wyjątki specyficzne dla usługi mogą dodawać dodatkowe pola. Na przykład StorageException dodaje 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 ... */
};

Wzorce i przykłady obsługi wyjątków

Używanie kodów błędów

Wyjątki usługi zawierają ErrorCode wartości, które mogą służyć do podejmowania decyzji dotyczących sposobu obsługi błędów. Oto przykład dotyczący usług Storage:

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

Obsługa podstawowych wyjątków

Podstawowy wzorzec obsługi wyjątków w zestawie 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
}

Obsługa błędów przejściowych

Niektóre usługi, takie jak Event Hubs, zawierają informacje o tym, czy błąd jest przejściowy, co pozwala na logikę ponawiania prób:

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

Zestaw SDK implementuje wewnętrzne zasady ponawiania prób dla błędów przejściowych, ale chcesz obsługiwać określone przypadki w kodzie aplikacji.

Obsługa błędów specyficznych dla usługi

W przypadku usług przechowywania (obiektów blob, plików, kolejek itp.) można obsługiwać błędy zarówno na podstawie kodów błędów, jak i kodów stanu 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;
    }
}

W przypadku operacji usługi Key Vault może być konieczne oddzielne obsługiwanie wyjątków uwierzytelniania:

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
}

Zagadnienia dotyczące bezpieczeństwa wątków

Azure SDK dla języka C++ gwarantuje, że metody instancji klienta są bezpieczne dla wątków i niezależne od siebie. Oznacza to, że można bezpiecznie używać wystąpienia klienta w wielu wątkach bez synchronizacji.

Podczas obsługi wyjątków między wątkami należy pamiętać:

  1. Obiekty wyjątków nie powinny być współużytkowane między wątkami, chyba że zostały prawidłowo zsynchronizowane
  2. Element RequestFailedException zawiera konstruktor kopii, który tworzy kopię głęboką, która może być używana podczas konieczności przekazywania informacji o wyjątkach między wątkami