TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7317 3.15K
🤓 Паника уронила весь fan-out воркер

История из боевых распределённых систем. Один кривой подписчик уронил доставку всем остальным, потому что паника в горутине без recover завершает весь процесс. Острая грань языка, про которую легко забыть.

➡️ Что случилось

Был шлюз вебхуков, который параллельно рассылал события десяткам подписчиков. У одного оказался кривой URL, который в редком случае приводил к панике в HTTP-клиенте вместо ошибки.

Раздача шла в голых горутинах без восстановления:
func fanOut(events []Event, subscribers []Subscriber) {
var wg sync.WaitGroup
for _, sub := range subscribers {
wg.Add(1)
go func(s Subscriber) {
defer wg.Done()
deliver(s, events) // паника здесь убивает весь процесс
}(sub)
}
wg.Wait()
}


В Go паника в любой горутине, которую не перехватили через recover, завершает всю программу. Не важно, сколько других горутин в этот момент делают полезную работу.

Про это легко забыть, потому что в туториалах паника обычно происходит в главной горутине, где последствия очевидны. Здесь же баг одного подписчика оборвал доставку всем.

➡️ Как починили

Изоляция паники стала структурным паттерном, а не заплаткой по случаю. Появилась обёртка safeGo:
func safeGo(fn func()) {
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("recovered panic: %v\n%s", r, debug.Stack())
}
}()
fn()
}()
}
func fanOut(events []Event, subscribers []Subscriber) {
var wg sync.WaitGroup
for _, sub := range subscribers {
wg.Add(1)
safeGo(func() {
defer wg.Done()
deliver(sub, events)
})
}
wg.Wait()
}


Теперь каждая долгоживущая или fan-out горутина проходит через обёртку вроде safeGo, и серверные gRPC-интерсепторы получили то же самое. Восстановление после паники переехало с верхнего HTTP-хендлера на каждую горутину, которую вы заводите сами.

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoToProduction
  • 👍 6
  • ❤ 2
More from @goproglib
  1. Sep 26, 2026🔥 В Go 1.27 появился portable SIMD До этого SIMD-оптимизации в Go требовали архитектурног…
  2. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
  3. Sep 25, 2026💡 Код работает. А data race уже есть В Go можно записать значение в одной горутине, прочи…
  4. Sep 23, 2026💥 TCP/IP: что происходит с данными в сети Когда Go-приложение отправляет данные по сети,…
  5. Sep 22, 2026🔴 Встроенные функции len, make, panic — встроенные функции Go, которые можно использовать…
  6. Sep 21, 2026🤩 Go с нуля: серия базовых шпаргалок Собрали путь от Hello, World! до goroutines, channel…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →