Python Programming

Sağlam Python Mikroservisleri Oluşturma

Dağıtık sistemlerin karmaşık manzarasında, bakımı kolay bir mimari ile hata ayıklama kâbusu arasındaki fark genellikle gözlemlenebilirlik ve hata yönetimi yatar. Python mikroservisleri ölçeklendikçe, temel print ifadelerine ve genel try-except bloklarına güvenmek sürdürülemez hale gelir. Dayanıklılığı sağlamak için ekiplerin yapılandırılmış günlük kaydı (structured logging) uygulaması ve özel istisna hiyerarşileri tanımlaması gerekir. Bu yaklaşım sadece veri akışını netleştirmez, aynı zamanda servis sınırları boyunca hata kurtarma süreçlerini de standartlaştırır.

Yapılandırılmış Günlük Kaydı İçin Gerekçe

Geleneksel günlük satırları yapılandırılmamış metinlerdir ve Elasticsearch veya Datadog gibi büyük ölçekli günlük birleştiricilerde sorgulanmalarını zorlaştırır. Yapılandırılmış günlük kaydı, verileri JSON nesneleri olarak biçimlendirir; bu sayede kırılgan regex ayrıştırmasına güvenmeden user_id, request_id veya service_name gibi belirli alanları dizine ekleyebilirsiniz.

Python için endüstri standardı kütüphanesi, standart logging modülüyle sorunsuz bir şekilde entegre olan structlog'dur. Her günlük girişine otomatik olarak bağlam eklemenize olanak tanır; böylece hata izleri her zaman doğru kullanıcı oturumuyla ilişkilendirilmiş olur.

import structlog
import logging
from logging.handlers import RotatingFileHandler

# Altta yatan standart kütüphane loglayıcısını yapılandırın
handler = RotatingFileHandler("app.log", maxBytes=10_000_000, backupCount=5)
handler.setFormatter(logging.Formatter('%(message)s'))

# JSON biçimlendirmesiyle structlog'u başlatın
structlog.configure(
    processors=[
        structlog.processors.add_log_level,
        structlog.processors.add_logger_name,
        structlog.processors.JSONRenderer()
    ],
    wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True,
)

logger = structlog.get_logger()

def process_order(order_id: str, user_id: str):
    # Bağlam, bu fonksiyondaki tüm günlük kayıtlara otomatik olarak eklenir
    logger.info("order_received", order_id=order_id, user_id=user_id)
    # İşleme simülasyonu
    logger.debug("processing_payload", payload_size=len(order_id))

Özel İstisna Hiyerarşileri Tasarlama

Dağıtık sistemler, basit mantık hatalarından farklı olan ağ zaman aşımı, servis kullanılabilirliği sorunları veya bozuk girdi gibi benzersiz başarısızlık modlarıyla karşı karşıyadır. ValueError veya RuntimeError gibi yerleşik istisnalara güvenmek, çağıran servise hiçbir anlamsal bağlam sağlamaz. Özel bir hiyerarşi, hataları kategorize etmenize ve bunları belirli HTTP durum kodlarına veya yeniden deneme stratejilerine haritamanıza olanak tanır.

Temel bir istisna sınıfı oluşturarak, zengin meta veri taşıyan belirli hataların bir ağacını oluşturabilirsiniz. Bu, otomatik yeniden denemeler ve devre kesiciler (circuit breakers) için hayati önem taşır.

class MicroserviceException(Exception):
    """Tüm mikroservis özel hataları için temel istisna."""
    def __init__(self, message: str, error_code: str, context: dict = None):
        super().__init__(message)
        self.error_code = error_code
        self.context = context or {}
        self.timestamp = None

class ServiceUnavailableException(MicroserviceException):
    """Aşağı akış bağımlılığı kullanılamadığında yükseltilir."""
    def __init__(self, service_name: str, retry_after: int):
        super().__init__(
            message=f"{service_name} servisi kullanılamıyor",
            error_code="ERR_SERVICE_UNAVAILABLE",
            context={"service": service_name, "retry_after": retry_after}
        )

class ValidationErrorException(MicroserviceException):
    """Girdi verisi iş mantığı doğrulamasını başarısız olduğunda yükseltilir."""
    def __init__(self, field: str, reason: str):
        super().__init__(
            message=f"{field} alanı için doğrulama başarısız",
            error_code="ERR_VALIDATION",
            context={"field": field, "reason": reason}
        )

Günlük Kaydı ve İstisnaları Entegre Etme

Bu desenlerin gerçek gücü, birleştirildiklerinde ortaya çıkar. Özel bir istisna yükseltildiğinde, günlük kaydı ara katmanı (middleware) istisnayı yakalayabilir, onu yapılandırılmış bağlamla zenginleştirebilir ve uygun düzeyde (örneğin, iş mantığı hataları için ERROR, kurtarılabilir zaman aşimleri için WARN) günlük kaydı oluşturabilir.

def handle_payment_request(order_id: str):
    try:
        if not order_id:
            raise ValidationErrorException("order_id", "Kimlik boş olamaz")
        # Harici çağrı simülasyonu
        raise ServiceUnavailableException("payment_gateway", 300)
    except MicroserviceException as e:
        logger.exception(
            "payment_handler_failed",
            error_code=e.error_code,
            error_details=e.context,
            original_exception=e.__class__.__name__
        )
        raise

Sonuç

Yapılandırılmış günlük kayıt ve özel istisna hiyerarşileri uygulamak sadece bir kodlama stili tercihi değil; güvenilir dağıtık Python mikroservisleri oluşturmak için temel bir gereksinimdir. Bu uygulamaları benimseyerek, geliştirme ekipleri olaylar sırasında Çözüm Süresinin Ortalamasını (MTTR) azaltır ve hata davranışlarının açık ve öngörülebilir olduğu, kendini belgeleyen bir kod tabanı oluşturur. Gelecek ölçeklenebilirlik için gerekli olan gözlemlenebilirlik temelini inşa etmek için bugün mevcut servislerinizi yeniden düzenlemeye başlayın.

Share: