İçeriğe geç
Muhammet Şafak
en
Soran: Oğuz Cevaplandı:

Go HTTP sunucusunda panic'i recovery middleware ile nasıl yönetirim?


Soru

Go ile yazılı HTTP API'mizde nil pointer dereference yüzünden beklenmedik bir panic oluştu. Bu panic tüm sürecin aniden kapanmasına ve o an içeride olan tüm HTTP isteklerinin drop edilmesine sebep oldu. Go'nun `recover()` mekanizmasıyla panic'leri yakalayan, loglayan ve istemciye zarif bir 500 dönen merkezi bir middleware'i nasıl kurarım?

Cevap

Kısa cevap: Tek bir handler’daki recover edilmemiş panic, tüm süreci çökertir ve o an içerideki bütün istekleri drop eder. Çözüm, her isteği bir recovery middleware’iyle sarmak — böylece bir isteğin panic’i o isteğe hapsolur.

Kısa cevap

Asıl mesele şu: Go’da bir goroutine panic’lerse ve kimse recover etmezse, program tamamen kapanır. Bir nil deref yüzünden binlerce sağlıklı istek de sizinle birlikte ölür. Servisi standart kütüphaneyle kurmanın detayını Go’da HTTP servisi yazmak yazısında anlatmıştım.

Neden

  1. Panic süreç seviyesindedir, istek seviyesinde değil. Recover edilmediğinde arıza yarıçapı tek isteği değil tüm süreci kapsar.

  2. Recover yalnızca kendi goroutine’ini yakalar. Handler içinde go func(){...}() açtıysanız, oradaki panic middleware’inizin recover’ına takılmaz.

  3. Sessizce yutulan panic, recover edilmemesi kadar tehlikelidir. Metrik yoksa aynı bug günlerce gizli kalır.

Ne yapmalı

  1. Her isteği defer recover() ile sarın. Middleware içinde defer func(){ if r := recover(); r != nil { /* logla + 500 yaz */ } }() kurun.

  2. Bu middleware’i zincirin en dışına koyun. Recovery en dıştaki katman olmalı ki kendisinden sonra gelen tüm handler ve middleware’lerin panic’lerini sarsın.

  3. Stack’i + request id’yi loglayın, ama içini sızdırmayın. debug.Stack() ile stack trace’i ve isteğin id’sini loglayın; istemciye generic bir 500 dönün.

  4. Panic’i görünür kılın — bir metrik basın. Her recover’da bir sayaç artırın.

  5. Açtığınız her goroutine’e kendi recover’ını verin. Aksi hâlde süreç yine ölür.

Sonuç: Ben olsam istek başına recover middleware + her goroutine için ayrı recover + metrik kurardım. İki uyarı: recover, beklenmedik bug’lar (nil deref) içindir, hata dönmenin yerine geçmez — beklenen hataları error ile dönün. Ve buna rağmen süreci yeniden başlatan bir supervisor tutun.

İlgili Yazılar

Etiketler: #Dayanıklılık#Go
Uzmanlık: Go Geliştirici
Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi