programowanieSenior Go Developer

Opowiedz, jak Go implementuje wbudowane funkcje recover i panic. Jaki jest właściwy porządek ich użycia dla bezpiecznego odzyskiwania w goroutine?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Go panika (panic) jest używana do sygnalizowania fatalnego błędu w programie. Po wywołaniu panic wykonywanie zaczyna się od unwind stosu i wywołania wszystkich funkcji deferred. Jeśli w stosie znajduje się funkcja z wywołaniem recover(), może ona przechwycić i obsłużyć panikę — ale recover działa tylko w swojej gorutinie i tylko po wywołaniu z defer.

Zalecany wzór na bezpieczne odzyskiwanie:

func safe(fn func()) { defer func() { if r := recover(); r != nil { fmt.Println("Odzyskano z paniki:", r) } }() fn() } go safe(func() { panic("fail!") // nie powoduje zatrzymania programu })

Ważne jest, aby pamiętać, że:

  • panic kończy wykonywanie bieżącej gorutiny aż do pierwszego recover
  • Recover działa tylko przy wywołaniu z defer wewnątrz tej samej gorutiny
  • Jeśli recover nie jest używany, panika spowoduje zakończenie całego programu

Pytanie pułapka

Czy recover może przechwycić panikę, która wystąpiła w innej gorutinie?

Odpowiedź: Nie, recover działa tylko w gorutinie, w której wystąpiła panika, i tylko jeśli został wywołany w odłożonej (defer) funkcji. Jeśli panika wystąpiła w jednej gorutinie, a recover jest wywoływany w innej — przechwycenie nie nastąpi, program awaryjnie zakończy wykonanie.

Przykład:

func main() { go func() { panic("w gorutinie") }() time.Sleep(time.Second) recover() // Nie zadziała! Panic zakończy program }

Przykłady rzeczywistych błędów z powodu braku znajomości szczegółów tematu


Historia

Programista zaimplementował obsługę błędów przy użyciu wzoru defer recover() tylko w funkcji głównej. Gdy panika wystąpiła wewnątrz worker'a w oddzielnej gorutinie, cały program awaryjnie zakończył działanie — błąd nie został przechwycony przez globalny recover.


Historia

W projekcie używano defer/recover do graceful shutdown serwera WWW, sądząc, że to wystarczy. Okazało się, że panika w jednej z gorutin logiki kończyła cały proces, ponieważ obsługa recover była umiejscowiona w niewłaściwym miejscu — konieczne było refaktoryzowanie całego puli workerów.


Historia

W wątku przetwarzania wiadomości wystąpiła panika z powodu niewłaściwego działania funkcji użytkownika. Programista oczekiwał, że jej "złapie" recover wyższego poziomu, ale nie zdawał sobie sprawy, że recover działa TYLKO z defer. W rezultacie serwis zawieszał się nieregularnie, gdy w kolejce pojawiała się nieprawidłowa wiadomość.