Menangani kesalahan yang dihasilkan oleh Azure SDK untuk Python

Membangun aplikasi cloud yang andal membutuhkan lebih dari sekadar mengimplementasikan fitur. Ini juga menuntut strategi penanganan kesalahan yang kuat. Saat Anda bekerja dengan sistem terdistribusi dan layanan cloud, aplikasi Anda harus siap untuk menangani skenario kegagalan dengan anggun.

Azure SDK untuk Python menyediakan model kesalahan komprehensif yang dirancang untuk membantu pengembang membangun aplikasi tangguh. Memahami model kesalahan ini sangat penting untuk:

  • Meningkatkan keandalan aplikasi dengan mengantisipasi dan menangani skenario kegagalan umum.
  • Meningkatkan pengalaman pengguna melalui pesan kesalahan yang bermakna dan degradasi yang anggun.
  • Menyederhanakan pemecahan masalah dengan menangkap dan mencatat informasi diagnostik yang relevan.

Artikel ini menjelajahi arsitektur kesalahan Azure SDK for Python dan memberikan panduan praktis untuk menerapkan penanganan kesalahan yang efektif di aplikasi Anda.

Bagaimana azure SDK untuk kesalahan model Python

Azure SDK untuk Python menggunakan model pengecualian hierarkis yang menyediakan kemampuan penanganan kesalahan umum dan spesifik. Inti dari model ini adalah AzureError, yang berfungsi sebagai kelas pengecualian dasar untuk semua kesalahan yang terkait dengan Azure SDK.

Hierarki pengecualian

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

Jenis pengecualian kunci

Kesalahan Description
AzureError Kelas pengecualian dasar untuk semua kesalahan Azure SDK. Gunakan pengecualian ini sebagai penampung umum saat Anda perlu menangani kesalahan apa pun yang berhubungan dengan Azure.
ClientAuthenticationError Dimunculkan ketika autentikasi gagal. Penyebab umum termasuk kredensial yang tidak valid, token kedaluwarsa, dan pengaturan autentikasi yang salah dikonfigurasi.
ResourceNotFoundError Dimunculkan saat mencoba mengakses sumber daya yang tidak ada. Pengecualian ini biasanya sesuai dengan respons HTTP 404.
ResourceExistsError Dimunculkan saat mencoba membuat sumber daya yang sudah ada. Pengecualian ini membantu mencegah penimpaan yang tidak disengaja.
ServiceRequestError Dimunculkan ketika SDK tidak dapat mengirim permintaan ke layanan. Penyebab umum termasuk masalah konektivitas jaringan, kegagalan resolusi Sistem Nama Domain, dan titik akhir layanan yang tidak valid.
ServiceResponseError Dimunculkan saat layanan mengembalikan respons tak terduga yang tidak dapat diproses SDK.
HttpResponseError Dinaikkan untuk respons kesalahan HTTP (kode status 4xx dan 5xx). Pengecualian ini menyediakan akses ke detail respons HTTP yang mendasar.

Skenario kesalahan umum

Memahami skenario kesalahan umum membantu Anda menerapkan strategi penanganan yang sesuai untuk setiap situasi.

Kesalahan autentikasi dan otorisasi

Kegagalan autentikasi terjadi ketika SDK tidak dapat memverifikasi identitas Anda:

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

Kesalahan otorisasi (biasanya HttpResponseError dengan 403 status) terjadi ketika Anda tidak memiliki izin:

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

Kesalahan sumber daya

Tangani sumber daya yang hilang dengan anggun:

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"

Cegah pembuatan sumber daya duplikat:

from azure.core.exceptions import ResourceExistsError

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

Kesalahan server

Tangani kegagalan sisi server dengan tepat:

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

Praktik terbaik untuk penanganan kesalahan

  • Gunakan penanganan pengecualian tertentu: Selalu tangkap pengecualian tertentu sebelum kembali ke yang umum:

    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}")
    
  • Terapkan strategi coba lagi yang sesuai: Beberapa kesalahan menjamin upaya coba lagi, sementara yang lain tidak.

    Jangan coba lagi pada:

    • 401 Tidak Sah (kegagalan autentikasi)
    • 403 Terlarang (kegagalan otorisasi)
    • 400 Permintaan Buruk (kesalahan klien)
    • 404 Tidak Ditemukan (kecuali Jika Anda mengharapkan sumber daya muncul)

    Pertimbangkan untuk mencoba kembali pada:

    • 408 Batas Waktu Permintaan
    • 429 Terlalu Banyak Permintaan (dengan backoff yang sesuai)
    • Kesalahan Server Internal 500
    • Gateway Buruk 502
    • 503 Layanan Tidak Tersedia
    • Batas Waktu Gateway 504
  • Mengekstrak informasi kesalahan yang bermakna

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

Mencoba kembali kebijakan dan ketahanan

Azure SDK menyertakan mekanisme coba lagi bawaan yang menangani kegagalan sementara secara otomatis.

Perilaku coba lagi default

Sebagian besar klien Azure SDK menyertakan kebijakan coba lagi default yang:

  • Coba lagi kesalahan koneksi dan kode status HTTP tertentu.
  • Gunakan backoff eksponensial dengan jitter.
  • Batasi jumlah upaya coba lagi.

Menyesuaikan kebijakan coba lagi

Jika perilaku default tidak sesuai dengan kasus penggunaan Anda, Anda dapat menyesuaikan kebijakan coba lagi:

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
)

Hindari menangani kesalahan jaringan dan waktu habis dengan perulangan kustom

Cobalah untuk menggunakan percobaan ulang bawaan untuk kesalahan jaringan dan waktu habis sebelum Anda menerapkan logika kustom Anda sendiri.

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

Menerapkan pola pemutus sirkuit

Untuk operasi penting, pertimbangkan untuk menerapkan pola pemutus sirkuit:

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

Memahami pesan kesalahan dan kode

Layanan Azure mengembalikan respons kesalahan terstruktur yang memberikan informasi penelusuran kesalahan yang berharga.

  • Mengurai respons kesalahan

    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()}")
    
  • Menangkap informasi diagnostik: Selalu ambil informasi diagnostik utama untuk pemecahan masalah:

    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
    
  • Pengelogan dan diagnostik: Aktifkan pengelogan tingkat SDK untuk pemecahan masalah terperinci:

    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)
    

    Untuk informasi selengkapnya tentang pengelogan, lihat Mengonfigurasi pengelogan di pustaka Azure untuk Python.

  • Gunakan pelacakan jaringan: Untuk penelusuran kesalahan mendalam, aktifkan pelacakan tingkat jaringan:

    Penting

    Pengelogan HTTP dapat menyertakan informasi sensitif seperti kunci akun di header dan kredensial lainnya. Pastikan untuk melindungi log ini untuk menghindari penyusupan keamanan.

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

Pertimbangan khusus untuk pemrograman asinkron

Saat Anda menggunakan klien asinkron, penanganan kesalahan memerlukan perhatian khusus.

  • Penanganan kesalahan asinkron dasar

    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
    
  • Menangani pembatalan

    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
    
  • Penanganan kesalahan bersamaan

    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
    

Ringkasan praktik terbaik

Penanganan kesalahan yang efektif di Azure SDK untuk aplikasi Python mengharuskan Anda untuk:

  • Mengantisipasi kegagalan: Aplikasi cloud harus mengharapkan dan menangani kegagalan parsial dengan anggun.
  • Gunakan penanganan pengecualian tertentu: Tangkap pengecualian tertentu seperti ResourceNotFoundError dan ClientAuthenticationError sebelum kembali ke penanganan umum AzureError .
  • Terapkan logika coba lagi cerdas: Gunakan kebijakan coba lagi bawaan atau sesuaikan berdasarkan kebutuhan Anda. Ingat bahwa tidak semua kesalahan harus memicu percobaan ulang.
  • Menangkap informasi diagnostik: Selalu catat ID permintaan, kode kesalahan, dan stempel waktu untuk pemecahan masalah yang efektif.
  • Berikan umpan balik pengguna yang bermakna: Ubah kesalahan teknis menjadi pesan yang mudah digunakan saat Anda mempertahankan detail teknis untuk dukungan.
  • Skenario kesalahan pengujian: Sertakan penanganan kesalahan dalam cakupan pengujian Anda untuk memastikan bahwa aplikasi Anda berulah dengan benar dalam kondisi kegagalan.