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 recoverCzy 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 }
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ść.