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

> Zincirin en dışına `defer recover()` koyun, stack'i request id ile loglayıp generic 500 dönün, metrik basın, her goroutine'e kendi recover'ını verin.

- Soruldu: 2026-06-01
- Yanıtlandı: 2026-06-04
- Soran: Oğuz
- Etiketler: dayaniklilik, go
- Kaynak: https://www.muhammetsafak.com.tr/sor-bakalim/go-da-panic-yonetimi-ve-recovery-middleware/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**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?


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

1. **Her isteği `defer recover()` ile sarın.** Middleware içinde `defer func(){ if r := recover(); r != nil { /* logla + 500 yaz */ } }()` kurun. 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 koyun.** 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ız.
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 ise generic bir `500 Internal Server Error` dönün. Hata detayını, dosya yollarını, stack'i kullanıcıya göstermeyin.
4. **Panic'i görünür kılın — bir metrik basın.** Her recover'da bir sayaç/metrik artırın. Panic'in sessizce yutulması, recover edilmemesi kadar tehlikelidir; recover edip metriği unutursanız aynı bug günlerce gizli kalır.
5. **`recover` yalnızca aynı goroutine'i yakalar — bunu unutmayın.** Handler içinde `go func(){...}()` açıyorsanız, o goroutine'deki panic sizin middleware'inizin recover'ına **takılmaz** ve yine tüm süreci öldürür. Açtığınız 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ün. Ve buna rağmen süreci yeniden başlatan bir supervisor tutun. HTTP servisini Go standart kütüphanesiyle yazmanın detayını hub'daki yazıda anlatıyorum.

## İlgili Yazılar

- [Go'da HTTP servisi yazmak: standart kütüphane yeter mi](/blog/go-da-http-servisi-yazmak-standart-kutuphane-yeter-mi/) — Blog
- [Birbirine bağımlı birden fazla işi, ilk hata hepsini iptal edecek şekilde errgroup ile mi yürütmeliyim?](https://www.muhammetsafak.com.tr/sor-bakalim/birbirine-bagimli-birden-fazla-isi-ilk-hata-hepsini-iptal-edecek-sekilde/) — Sor Bakalım
- [İç içe geçmiş servis çağrılarında context iptalini doğru şekilde nasıl yayarım?](https://www.muhammetsafak.com.tr/sor-bakalim/ic-ice-gecmis-servis-cagrilarinda-context-iptalini-dogru-sekilde-nasil-yayarim/) — Sor Bakalım
- [Goroutine sızıntılarını uzun süre çalışan bir Go servisinde nasıl tespit edip önlerim?](https://www.muhammetsafak.com.tr/sor-bakalim/goroutine-sizintilarini-uzun-sure-calisan-bir-go-servisinde-nasil-tespit-edip/) — Sor Bakalım
