Serverless & Hata Yönetimi 4 dk okuma 18 okunma

Cloud Functions'te Retry ve DLQ

Cloud Functions'te retry ve DLQ davranışı, fonksiyonun tetikleme türüne (HTTP vs. event-driven) ve kullanılan nesil (Gen 1 vs. Gen 2) ile yönetim modeline göre değişir. HTTP fonksiyonlarında otomatik retry yoktur; Gen 2 event-driven fonksiyonlarda retry --retry bayrağıyla etkinleştirilir ve DLQ için yönetilen Pub/Sub aboneliği yerine kendi push aboneliğinizi kurmanız gerekir.

Cloud Functions'te Retry ve DLQ

Cloud Functions'te Retry ve DLQ

Serverless fonksiyonlarda hata yönetimi, "fonksiyon başarısız olduğunda ne olacak?" sorusuyla başlar. Google Cloud Functions'ta bu sorunun cevabı, fonksiyonun tetikleme türüne (HTTP mi, event-driven mi) ve nesline (Gen 1 mi, Gen 2 mi) göre değişir. Özellikle Gen 2'de retry ve Dead Letter Queue (DLQ) yönetimi, Pub/Sub abonelik modeline dayandığı için Gen 1'den önemli ölçüde farklıdır.


1. HTTP Fonksiyonları: Otomatik Retry Yok

HTTP trigger'lı fonksiyonlarda otomatik retry mekanizması yoktur. Fonksiyon bir hata döndürürse (5xx), hata doğrudan çağırana iletilir. Yeniden deneme sorumluluğu çağıran taraftadır . Bu nedenle, HTTP fonksiyonlarında retry stratejisi istemci tarafında (retry policy, exponential backoff) veya fonksiyonun önüne konulan bir API Gateway katmanında yönetilmelidir.


2. Event-Driven Fonksiyonlar (Gen 2): Retry Davranışı

Gen 2 event-driven fonksiyonlarda (Pub/Sub, Eventarc, Cloud Storage, Firestore tetikleyicileri) retry davranışı, altta yatan Pub/Sub aboneliği veya Eventarc trigger'ı tarafından yönetilir .

Kritik Ayrım: Varsayılan Retry Durumu

Gen 2 fonksiyonlarda retry'ın varsayılan durumu, kaynağa göre değişir ve bu konuda kafa karışıklığı yaygındır:

  • Pub/Sub trigger (gcloud ile deploy edilen): gcloud functions deploy --gen2 --trigger-topic=... ile deploy edilen fonksiyonlarda retry varsayılan olarak kapalıdır. Etkinleştirmek için --retry bayrağı eklenmelidir .

  • Eventarc trigger (Cloud Storage, Firestore vb.): Retry, trigger'ın retry politikası tarafından kontrol edilir ve yine --retry ile etkinleştirilir .

--retry Etkinleştirildiğinde Ne Olur?

--retry bayrağı eklendiğinde, Cloud Run functions başarısız event-driven çağrıları 24 saate kadar, 10 ila 600 saniye arasında üstel geri çekilme (exponential backoff) ile yeniden dener .

Fonksiyonun Sorumluluğu: Fonksiyon başarıyla dönerse (ACK), mesaj işlenmiş sayılır ve bir daha gönderilmez. Fonksiyon hata fırlatırsa veya reddedilmiş bir promise dönerse, sistem bunu "başarısız oldu, lütfen tekrar dene" sinyali olarak alır .


3. DLQ (Dead Letter Queue) Yapılandırması: Gen 2'de Yönetilen Abonelik Sorunu

Gen 2 fonksiyonları --trigger-topic ile deploy ettiğinizde, Google sizin adınıza bir Pub/Sub aboneliği oluşturur ve yönetir. Bu yönetilen abonelik üzerinde DLQ politikası doğrudan yapılandırılamaz .

Çözüm: Kendi Push Aboneliğinizi Yönetin

DLQ kullanmak istiyorsanız, yönetilen trigger yerine kendi Pub/Sub push aboneliğinizi oluşturmanız ve fonksiyonunuzu HTTP trigger olarak deploy etmeniz gerekir .

Adım Adım DLQ Kurulumu:

Adım 1: DLQ Topic ve Aboneliği Oluşturun

bash

gcloud pubsub topics create my-topic-dead-letter
gcloud pubsub subscriptions create my-topic-dead-letter-sub \
  --topic=my-topic-dead-letter \
  --ack-deadline=120

Adım 2: Pub/Sub Servis Hesabına İzin Verin

Pub/Sub servis hesabının DLQ topic'ine publish etme ve orijinal abonelikten mesaj onaylama yetkisi olmalıdır :

bash

PROJECT_NUMBER=$(gcloud projects describe my-project --format="value(projectNumber)")
PUBSUB_SA="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"

gcloud pubsub topics add-iam-policy-binding my-topic-dead-letter \
  --member="serviceAccount:${PUBSUB_SA}" \
  --role="roles/pubsub.publisher"

gcloud pubsub subscriptions add-iam-policy-binding my-subscription-name \
  --member="serviceAccount:${PUBSUB_SA}" \
  --role="roles/pubsub.subscriber"

Adım 3: DLQ Politikasını Yapılandırın

--max-delivery-attempts parametresi, mesajın DLQ'ya taşınmadan önce toplam kaç kez teslim edileceğini belirtir. Örneğin 5, "ilk deneme + 5 ek deneme" değil, yaklaşık 5 toplam teslimat anlamına gelir :

bash

gcloud pubsub subscriptions update my-subscription-name \
  --dead-letter-topic=my-topic-dead-letter \
  --max-delivery-attempts=5

4. Retry-Aware Fonksiyon Yazma: Geçici vs. Kalıcı Hatalar

Retry mekanizmasını etkinleştirdiğinizde, fonksiyonunuzun geçici hatalar (ağ sorunu, rate limit) ile kalıcı hatalar (geçersiz veri, iş kuralı ihlali) arasında ayrım yapması kritiktir. Geçici hatalar retry'a değer; kalıcı hatalar ise sonsuza kadar denenmemelidir .

Desen: Kalıcı Hataları DLQ'ya Gönderin, Geçici Hatalarda Retry'a İzin Verin

csharp

// .NET örneği (kavramsal)
public async Task ProcessEvent(CloudEvent cloudEvent)
{
    var deliveryAttempt = cloudEvent.Data.DeliveryAttempt ?? 1;
    
    try
    {
        // İş mantığı...
    }
    catch (PermanentException ex)
    {
        // Kalıcı hata: DLQ'ya gönder, retry'ı durdur
        await _deadLetterPublisher.PublishAsync(cloudEvent);
        return; // Hata fırlatma → ACK → retry durur
    }
    catch (TransientException ex)
    {
        // Geçici hata: hata fırlat → retry tetiklenir
        throw;
    }
}

Idempotency (Yinelenebilirlik): At-least-once teslimat nedeniyle aynı mesaj birden fazla kez gelebilir. Fonksiyonunuz, aynı mesajı iki kez işlemenin zararsız olduğundan emin olmalıdır (message ID ile deduplication) .


5. Ne Zaman Hangi Yaklaşım?

Senaryo Öneri
HTTP fonksiyonu, basit hata yönetimi Retry'ı istemci tarafında yönetin
Gen 2 event-driven, sadece retry yeterli --retry bayrağı ile managed retry (24 saat, üstel backoff)
Gen 2 event-driven, DLQ gerekli Kendi Pub/Sub push aboneliğinizi yönetin + --dead-letter-topic
Kalıcı hataların birikmesini istemiyorsunuz Retry-aware fonksiyon yazın; kalıcı hataları DLQ'ya yönlendirin

6. En İyi Pratikler

Pratik Açıklama
Hata türlerini ayırt edin Geçici hatalarda throw, kalıcı hatalarda DLQ'ya gönderip return edin
Idempotency sağlayın Message ID ile deduplication yapın
DLQ'yu izleyin DLQ'daki mesajları manuel inceleyin; kalıcı sorunları giderin
max-delivery-attempts değerini doğru anlayın Toplam teslimat sayısıdır; "retry sayısı" değil
Yönetilen trigger ile DLQ'yu karıştırmayın --trigger-topic ile DLQ aynı anda kullanılamaz; kendi push aboneliğinizi kurun

Sonuç

Cloud Functions'te retry ve DLQ, tetikleme türüne ve yönetim modeline göre farklılaşır. HTTP fonksiyonlarında otomatik retry yoktur; sorumluluk çağırandadır. Gen 2 event-driven fonksiyonlarda --retry ile 24 saate kadar üstel backofflu retry etkinleştirilebilir, ancak DLQ kullanmak için yönetilen trigger yerine kendi Pub/Sub push aboneliğinizi yönetmeniz gerekir. Retry-aware fonksiyon yazarak geçici ve kalıcı hataları ayırt etmek, hem gereksiz retry'ları önler hem de kalıcı hataların DLQ'da birikmesini sağlar. Unutmayın: Retry, geçici sorunlar içindir; kalıcı hatalar için DLQ ve manuel müdahale şarttır.

Tüm yazılar Soru ya da yorumun mu var? Yaz