İç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.

Asıl mesele şu: Go’da bir goroutine panik’lerse ve kimse recover etmezse, program tamamen kapanır. Bir nil deref yüzünden binlerce sağlıklı istek de seninle birlikte ölür.

  1. Her isteği defer recover() ile sar. Middleware içinde defer func(){ if r := recover(); r != nil { /* logla + 500 yaz */ } }() kur. Böylece tek bir istekteki panic yakalanır, süreç ayakta kalır ve diğer istekler etkilenmez.
  2. Bu middleware’i zincirin en dışına koy. Recovery, en dıştaki (outermost) katman olmalı ki kendisinden sonra gelen tüm handler ve middleware’lerin panic’lerini sarsın. İçeride kalırsa, dışarıdaki bir panic’i kaçırırsın.
  3. Stack’i + request id’yi logla, ama içini sızdırma. debug.Stack() ile stack trace’i ve isteğin id’sini logla; istemciye ise generic bir 500 Internal Server Error dön. Hata detayını, dosya yollarını, stack’i kullanıcıya gösterme.
  4. Panic’i görünür kıl — bir metrik bas. Her recover’da bir sayaç/metrik artır. Panic’in sessizce yutulması, recover edilmemesi kadar tehlikelidir; recover edip metriği unutursan aynı bug günlerce gizli kalır.
  5. recover yalnızca aynı goroutine’i yakalar — bunu unutma. Handler içinde go func(){...}() açıyorsan, o goroutine’deki panic senin middleware’inin recover’ına takılmaz ve yine tüm süreci öldürür. Açtığın her goroutine’in kendi recover’ı olmalı.

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. Ve buna rağmen süreci yeniden başlatan bir supervisor tut. HTTP servisini Go standart kütüphanesiyle yazmanın detayını hub’daki yazıda anlatıyorum.

İlgili Yazılar

Etiketler: #dayanıklılık#go
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