Celery Görevlerinde Redis ile Dağıtık Kilitleme (Distributed Locking)

Dağıtık sistemlerde, birden fazla worker'ın aynı kritik kod bloğunu aynı anda çalıştırmasını engellemek için kilitleme (locking) mekanizmalarına ihtiyaç duyulur. Python ekosisteminde, bu iş için en popüler çözümlerden biri Redis tabanlı kilitlerdir. Redis hızlı ve güvenilir olduğu için tercih edilir.

Bu rehberde, projede uygulanan tekrar kullanılabilir context manager yaklaşımıyla, Celery görevlerinde Redis tabanlı dağıtık kilidin nasıl uygulanacağını ve kullanılacağını anlatıyoruz.


Neden Dağıtık Kilit Kullanılır?

Birden fazla Celery worker çalıştırdığınızda, aynı zamanlanmış veya tetiklenmiş görevin birden fazla worker tarafından aynı anda alınması riski vardır. Bu, tekrarlı işlem, veri bozulması veya yarış durumlarına (race condition) yol açabilir. Dağıtık kilitleme, aynı anda sadece bir worker'ın kritik kodu çalıştırmasını garanti eder.


Uygulama Özeti

Redis, dağıtık kilit için arka uç (backend) olarak kullanılır. Kilit işlemi bir context manager ile yönetilir. Böylece kodunuz temiz olur ve hata olsa bile kilit her zaman serbest bırakılır.

1. redis_lock Context Manager'ı

app/utils/redis_lock.py dosyasına aşağıdaki yardımcı fonksiyonu ekleyin:

from contextlib import contextmanager
import logging

logger = logging.getLogger(__name__)

@contextmanager
def redis_lock(client, lock_key, timeout=600):
    """
    Redis kilidi almak ve bırakmak için context manager.
    Argümanlar:
        client: Redis client nesnesi.
        lock_key (str): Kilit anahtarı.
        timeout (int): Kilidin saniye cinsinden süresi.
    Yield:
        bool: Kilit alındıysa True, alınamadıysa False.
    """
    lock = client.lock(lock_key, timeout=timeout)
    acquired = lock.acquire(blocking=False)
    try:
        if acquired:
            yield True
        else:
            yield False
    finally:
        if acquired:
            lock.release()
            logger.info("Redis kilidi serbest bırakıldı.")

2. Celery Görevinde Kilidi Kullanmak

Örneğin app/tasks/email_pending_tasks.py dosyasında, sadece bir worker'ın görevi işlemesini sağlamak için context manager'ı şu şekilde kullanın:

import logging
from config.celery_config import celery_app, get_redis_url
from services.email_service import EmailService
import redis
from app.utils.redis_lock import redis_lock

logger = logging.getLogger(__name__)

def get_redis_client():
    redis_url = get_redis_url()
    return redis.Redis.from_url(redis_url)

@celery_app.task(name='process_pending_emails', queue='high')
def process_pending_emails():
    """
    Aynı anda sadece bir worker'ın pending emailleri işlemesini sağlamak için Redis kilidi kullanır.
    """
    logger.info("Pending emaillerin işlenmesi başlatıldı")
    redis_client = get_redis_client()
    lock_key = "process_pending_emails_lock"
    # Kilit süresi: 30 dakika (1800 saniye)
    with redis_lock(redis_client, lock_key, timeout=1800) as acquired:
        if not acquired:
            logger.info("Başka bir worker şu anda pending emailleri işliyor. Bu worker beklemeden çıkıyor.")
            return
        try:
            email_service = EmailService()
            email_service.process_all_pending_emails()
        except Exception as e:
            logger.error(f"Emailler işlenirken hata oluştu: {str(e)}")
            raise  # Hatanın Celery tarafından işlenmesi için tekrar fırlat
    logger.info("Pending emaillerin işlenmesi tamamlandı")

En İyi Uygulama Önerileri

  • Uygun bir timeout belirleyin: Kilit süresi, görevin beklenen maksimum süresinden uzun olmalı ama gereksiz yere uzun olmamalı. Böylece worker çökse bile kilit sonsuza kadar kalmaz.
  • Her zaman context manager kullanın: Hata olsa bile kilidin serbest bırakılması garanti olur.
  • Her kritik işlem için farklı lock anahtarı kullanın: Birden fazla kilit gerektiren görevleriniz varsa, her biri için farklı anahtar kullanın.
  • Kilit işlemlerini loglayın: Kilit alımı ve bırakılması loglanırsa, hata ayıklama ve izleme kolaylaşır.

Dağıtık Kilit Ne Zaman Kullanılır?

  • Üst üste binmemesi gereken zamanlanmış görevler (ör: toplu işler, e-posta gönderimi, rapor üretimi)
  • Paylaşılan kaynakları veya dış sistemleri değiştiren işlemler
  • Çift işlem yapılmasının sorun yaratacağı her senaryo

Sonuç

Redis ile dağıtık kilitleme, Celery ile dağıtık çalışan ortamlarda aynı anda sadece bir worker'ın kritik kodu çalıştırmasını sağlamak için basit ve etkili bir yöntemdir. Kilit mantığını tekrar kullanılabilir bir context manager ile sarmak, kodunuzu temiz, güvenli ve bakımı kolay hale getirir.


Kaynaklar:

Read more

Docker ile Production Ortamına Deployment - Part 2

Docker ile Production Ortamına Deployment - Part 2

İçindekiler * Giriş * Uygulama Deploymentları * CI/CD Pipeline Kurulumu * Monitoring ve Logging * Otomatik Backup * Güvenlik Önlemleri Giriş Part 1'de temel altyapımızı kurduk ve Caddy web sunucumuzu yapılandırdık. Bu bölümde uygulamalarımızı deploy edecek, CI/CD pipeline kuracak ve monitoring sistemini oluşturacağız. Uygulama Deploymentları API Uygulaması API uygulamamız için docker-compose.yml:

By Aykut Asil
Docker ile Production Ortamına Deployment - Part 1

Docker ile Production Ortamına Deployment - Part 1

İçindekiler * Giriş * Web Sunucusu Seçimi: Caddy vs Nginx * Gereksinimler * Başlangıç Kurulumları * Proje Yapısı * Caddy Web Sunucusu Kurulumu * Network Oluşturma * Güvenlik Ayarları Giriş Bu makalede, bir web uygulamasını Docker kullanarak DigitalOcean Droplet üzerinde nasıl deploy edeceğimizi öğreneceğiz. İlk bölümde temel kurulumları ve Caddy web sunucusu yapılandırmasını ele alacağız. Web Sunucusu Seçimi:

By Aykut Asil
Slack ve GitHub Actions ile Otomatik Dağıtım Bildirimleri

Slack ve GitHub Actions ile Otomatik Dağıtım Bildirimleri

Yazılım geliştirme süreçlerinde, dağıtım işlemleri sırasında ekibin bilgilendirilmesi, sorunsuz iş birliği ve hata takibi için kritik öneme sahiptir. GitHub Actions ile Slack’i entegre ederek, dağıtım sürecinin başlangıcı, başarılı bir şekilde tamamlanması veya hata durumları için ekibinize otomatik bildirimler gönderebilirsiniz. Bu makalede, bunu nasıl yapabileceğinizi adım adım anlatıyoruz. Neden Slack

By Aykut Asil