Dela via


Hantera fel som skapats av Azure SDK för Python

Att skapa tillförlitliga molnprogram kräver mer än att bara implementera funktioner. Det kräver också robusta strategier för felhantering. När du arbetar med distribuerade system och molntjänster måste ditt program vara redo att hantera felscenarier på ett korrekt sätt.

Azure SDK för Python innehåller en omfattande felmodell som är utformad för att hjälpa utvecklare att skapa motståndskraftiga program. Det är viktigt att förstå den här felmodellen för:

  • Förbättra programmets tillförlitlighet genom att förutse och hantera vanliga felscenarier.
  • Förbättra användarupplevelsen genom meningsfulla felmeddelanden och graciös försämring.
  • Förenkla felsökningen genom att samla in och logga relevant diagnostikinformation.

Den här artikeln utforskar Azure SDK för Pythons felarkitektur och ger praktisk vägledning för att implementera effektiv felhantering i dina program.

Så här felar Azure SDK för Python-modeller

Azure SDK för Python använder en hierarkisk undantagsmodell som tillhandahåller allmänna och specifika funktioner för felhantering. Kärnan i den här modellen är AzureError, som fungerar som bas undantagsklass för alla fel relaterade till Azure SDK.

Undantagshierarki

AzureError
├── ClientAuthenticationError
├── ResourceNotFoundError
├── ResourceExistsError
├── ResourceModifiedError
├── ResourceNotModifiedError
├── ServiceRequestError
├── ServiceResponseError
└── HttpResponseError

Viktiga undantagstyper

Error Description
AzureError Den grundläggande undantagsklassen för alla Azure SDK-fel. Använd det här undantaget som en catchall när du behöver hantera azure-relaterade fel.
ClientAuthenticationError Utlöses när autentiseringen misslyckas. Vanliga orsaker är ogiltiga autentiseringsuppgifter, förfallna token och felkonfigurerade autentiseringsinställningar.
ResourceNotFoundError Utlöses när du försöker komma åt en resurs som inte finns. Det här undantaget motsvarar vanligtvis HTTP 404-svar.
ResourceExistsError Utlöses när du försöker skapa en resurs som redan finns. Det här undantaget hjälper till att förhindra oavsiktliga överskrivningar.
ServiceRequestError Utlöses när SDK:t inte kan skicka en begäran till tjänsten. Vanliga orsaker är problem med nätverksanslutningar, problem med systemmatchning av domännamn och ogiltiga tjänstslutpunkter.
ServiceResponseError Utlöses när tjänsten returnerar ett oväntat svar som SDK inte kan bearbeta.
HttpResponseError Upphöjt för HTTP-felsvar (statuskoderna 4xx och 5xx). Det här undantaget ger åtkomst till den underliggande HTTP-svarsinformationen.

Vanliga felscenarier

Genom att förstå vanliga felscenarier kan du implementera lämpliga hanteringsstrategier för varje situation.

Autentiserings- och auktoriseringsfel

Autentiseringsfel uppstår när SDK:t inte kan verifiera din identitet:

from azure.core.exceptions import ClientAuthenticationError
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient

try:
    credential = DefaultAzureCredential()
    blob_service = BlobServiceClient(
        account_url="https://myaccount.blob.core.windows.net",
        credential=credential
    )
    # Attempt to list containers
    containers = blob_service.list_containers()
except ClientAuthenticationError as e:
    print(f"Authentication failed: {e.message}")
    # Don't retry - fix credentials first

Auktoriseringsfel (vanligtvis HttpResponseError med 403 status) inträffar när du saknar behörighet:

from azure.core.exceptions import HttpResponseError

try:
    blob_client.upload_blob(data)
except HttpResponseError as e:
    if e.status_code == 403:
        print("Access denied. Check your permissions.")
    else:
        raise

Resursfel

Hantera saknade resurser på ett korrekt sätt:

from azure.core.exceptions import ResourceNotFoundError

try:
    blob_client = container_client.get_blob_client("myblob.txt")
    content = blob_client.download_blob().readall()
except ResourceNotFoundError:
    print("Blob not found. Using default content.")
    content = b"default"

Förhindra att dubbletter av resurser skapas:

from azure.core.exceptions import ResourceExistsError

try:
    container_client.create_container()
except ResourceExistsError:
    print("Container already exists.")
    # Continue with existing container

Serverfel

Hantera fel på serversidan på rätt sätt:

from azure.core.exceptions import HttpResponseError

try:
    result = client.process_data(large_dataset)
except HttpResponseError as e:
    if 500 <= e.status_code < 600:
        print(f"Server error ({e.status_code}). The service may be temporarily unavailable.")
        # Consider retry logic here
    else:
        raise

Metodtips för felhantering

  • Använd specifik undantagshantering: Fånga alltid specifika undantag innan du återgår till allmänna undantag:

    from azure.core.exceptions import (
        AzureError,
        ClientAuthenticationError,
        ResourceNotFoundError,
        HttpResponseError
    )
    
    try:
        # Azure SDK operation
        result = client.get_resource()
    except ClientAuthenticationError:
        # Handle authentication issues
        print("Please check your credentials")
    except ResourceNotFoundError:
        # Handle missing resources
        print("Resource not found")
    except HttpResponseError as e:
        # Handle specific HTTP errors
        if e.status_code == 429:
            print("Rate limited. Please retry later.")
        else:
            print(f"HTTP error {e.status_code}: {e.message}")
    except AzureError as e:
        # Catch-all for other Azure errors
        print(f"Azure operation failed: {e}")
    
  • Implementera lämpliga återförsöksstrategier: Vissa fel garanterar återförsök, medan andra inte gör det.

    Försök inte igen:

    • 401 Obehörig (autentiseringsfel)
    • 403 Förbjudet (auktoriseringsfel)
    • 400 Felaktig begäran (klientfel)
    • 404 Hittades inte (om du inte förväntar dig att resursen ska visas)

    Överväg att försöka igen:

    • Tidsgräns för 408-begäran
    • 429 För många begäranden (med lämplig backoff)
    • 500 Internt serverfel
    • 502 Felaktig gateway
    • 503 Tjänsten är inte tillgänglig
    • Tidsgräns för 504 Gateway
  • Extrahera meningsfull felinformation

    from azure.core.exceptions import HttpResponseError
    
    try:
        client.perform_operation()
    except HttpResponseError as e:
        # Extract detailed error information
        print(f"Status code: {e.status_code}")
        print(f"Error message: {e.message}")
        print(f"Error code: {e.error.code if e.error else 'N/A'}")
    
        # Request ID is crucial for Azure support
        if hasattr(e, 'response') and e.response:
            request_id = e.response.headers.get('x-ms-request-id')
            print(f"Request ID: {request_id}")
    

Återförsöksprinciper och motståndskraft

Azure SDK innehåller inbyggda mekanismer för återförsök som hanterar tillfälliga fel automatiskt.

Standardbeteende för återförsök

De flesta Azure SDK-klienter innehåller standardprinciper för återförsök som:

  • Försök igen vid anslutningsfel och specifika HTTP-statuskoder.
  • Använd exponentiell backoff med jitter.
  • Begränsa antalet återförsök.

Anpassa återförsöksprinciper

Om standardbeteendet inte passar ditt användningsfall kan du anpassa återförsöksprincipen:

from azure.storage.blob import BlobServiceClient
from azure.core.pipeline.policies import RetryPolicy

# Create a custom retry policy
retry_policy = RetryPolicy(
    retry_total=5,  # Maximum retry attempts
    retry_backoff_factor=2,  # Exponential backoff factor
    retry_backoff_max=60,  # Maximum backoff time in seconds
    retry_on_status_codes=[408, 429, 500, 502, 503, 504]
)

# Apply to client
blob_service = BlobServiceClient(
    account_url="https://myaccount.blob.core.windows.net",
    credential=credential,
    retry_policy=retry_policy
)

Undvik att hantera nätverks- och tidsgränsfel med anpassade loopar

Försök att använda inbyggda återförsök för nätverks- och tidsgränsfel innan du implementerar din egen anpassade logik.

from azure.core.exceptions import ServiceRequestError
import time

# Avoid this approach if possible
max_retries = 3
retry_count = 0

while retry_count < max_retries:
    try:
        response = client.get_secret("mysecret")
        break
    except ServiceRequestError as e:
        retry_count += 1
        if retry_count >= max_retries:
            raise
        print(f"Network error. Retrying... ({retry_count}/{max_retries})")
        time.sleep(2 ** retry_count)  # Exponential backoff

Implementera kretsbrytarmönster

För kritiska åtgärder bör du överväga att implementera kretsbrytarmönster:

class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=60):
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.failure_count = 0
        self.last_failure_time = None
        self.state = 'closed'  # closed, open, half-open
    
    def call(self, func, *args, **kwargs):
        if self.state == 'open':
            if time.time() - self.last_failure_time > self.recovery_timeout:
                self.state = 'half-open'
            else:
                raise Exception("Circuit breaker is open")
        
        try:
            result = func(*args, **kwargs)
            if self.state == 'half-open':
                self.state = 'closed'
                self.failure_count = 0
            return result
        except Exception as e:
            self.failure_count += 1
            self.last_failure_time = time.time()
            
            if self.failure_count >= self.failure_threshold:
                self.state = 'open'
            
            raise e

Förstå felmeddelanden och koder

Azure-tjänster returnerar strukturerade felsvar som ger värdefull felsökningsinformation.

  • Analyserar felmeddelanden

    from azure.core.exceptions import HttpResponseError
    import json
    
    try:
        client.create_resource(resource_data)
    except HttpResponseError as e:
        # Many Azure services return JSON error details
        if e.response and e.response.text():
            try:
                error_detail = json.loads(e.response.text())
                print(f"Error code: {error_detail.get('error', {}).get('code')}")
                print(f"Error message: {error_detail.get('error', {}).get('message')}")
    
                # Some services provide additional details
                if 'details' in error_detail.get('error', {}):
                    for detail in error_detail['error']['details']:
                        print(f"  - {detail.get('code')}: {detail.get('message')}")
            except json.JSONDecodeError:
                print(f"Raw error: {e.response.text()}")
    
  • Samla in diagnostikinformation: Samla alltid in viktig diagnostikinformation för felsökning.

    import logging
    from azure.core.exceptions import AzureError
    
    logger = logging.getLogger(__name__)
    
    try:
        result = client.perform_operation()
    except AzureError as e:
        # Log comprehensive error information
        logger.error(
            "Azure operation failed",
            extra={
                'error_type': type(e).__name__,
                'error_message': str(e),
                'operation': 'perform_operation',
                'timestamp': datetime.utcnow().isoformat(),
                'request_id': getattr(e.response, 'headers', {}).get('x-ms-request-id') if hasattr(e, 'response') else None
            }
        )
        raise
    
  • Loggning och diagnostik: Aktivera loggning på SDK-nivå för detaljerad felsökning:

    import logging
    import sys
    
    # Configure logging for Azure SDKs
    logging.basicConfig(level=logging.DEBUG)
    
    # Enable HTTP request/response logging
    logging.getLogger('azure.core.pipeline.policies.http_logging_policy').setLevel(logging.DEBUG)
    
    # For specific services
    logging.getLogger('azure.storage.blob').setLevel(logging.DEBUG)
    logging.getLogger('azure.identity').setLevel(logging.DEBUG)
    

    Mer information om loggning finns i Konfigurera loggning i Azure-biblioteken för Python.

  • Använd nätverksspårning: För djup felsökning aktiverar du spårning på nätverksnivå:

    Viktigt!

    HTTP-loggning kan innehålla känslig information, till exempel kontonycklar i rubriker och andra autentiseringsuppgifter. Se till att skydda loggarna för att undvika att äventyra säkerheten.

    from azure.storage.blob import BlobServiceClient
    
    # Enable network tracing
    blob_service = BlobServiceClient(
        account_url="https://myaccount.blob.core.windows.net",
        credential=credential,
        logging_enable=True,  # Enable logging
        logging_body=True     # Log request/response bodies (careful with sensitive data)
    )
    

Särskilda överväganden för asynkron programmering

När du använder asynkrona klienter kräver felhantering särskild uppmärksamhet.

  • Grundläggande asynkron felhantering

    import asyncio
    from azure.core.exceptions import AzureError
    
    async def get_secret_async(client, secret_name):
        try:
            secret = await client.get_secret(secret_name)
            return secret.value
        except ResourceNotFoundError:
            print(f"Secret '{secret_name}' not found")
            return None
        except AzureError as e:
            print(f"Error retrieving secret: {e}")
            raise
    
  • Hantera annulleringar

    async def long_running_operation(client):
        try:
            result = await client.start_long_operation()
            # Wait for completion
            final_result = await result.result()
            return final_result
        except asyncio.CancelledError:
            print("Operation cancelled")
            # Cleanup if necessary
            if hasattr(result, 'cancel'):
                await result.cancel()
            raise
        except AzureError as e:
            print(f"Operation failed: {e}")
            raise
    
  • Samtidig felhantering

    async def process_multiple_resources(client, resource_ids):
        tasks = []
        for resource_id in resource_ids:
            task = client.get_resource(resource_id)
            tasks.append(task)
    
        results = []
        errors = []
    
        # Use gather with return_exceptions to handle partial failures
        outcomes = await asyncio.gather(*tasks, return_exceptions=True)
    
        for resource_id, outcome in zip(resource_ids, outcomes):
            if isinstance(outcome, Exception):
                errors.append((resource_id, outcome))
            else:
                results.append(outcome)
    
        # Process successful results and errors appropriately
        if errors:
            print(f"Failed to process {len(errors)} resources")
            for resource_id, error in errors:
                print(f"  - {resource_id}: {error}")
    
        return results
    

Sammanfattning av metodtips

Effektiv felhantering i Azure SDK för Python-program kräver att du:

  • Förutse fel: Molnprogram måste förvänta sig och hantera partiella fel på ett korrekt sätt.
  • Använd specifik undantagshantering: Fånga specifika undantag som ResourceNotFoundError och ClientAuthenticationError innan du återgår till allmän AzureError hantering.
  • Implementera logik för smart återförsök: Använd inbyggda återförsöksprinciper eller anpassa dem baserat på dina behov. Kom ihåg att inte alla fel ska utlösa återförsök.
  • Samla in diagnostikinformation: Logga alltid begärande-ID,felkoder och tidsstämplar för effektiv felsökning.
  • Ge meningsfull användarfeedback: Omvandla tekniska fel till användarvänliga meddelanden samtidigt som du bevarar teknisk information för support.
  • Testfelscenarier: Inkludera felhantering i testtäckningen för att säkerställa att programmet fungerar korrekt under feltillstånd.