Какие последствия для всей программы имеет неперехваченная паника в горутине?
Неперехваченная паника в любой горутине приводит к завершению всей Go-программы, а не только этой горутины. Перехватить её можно только в той же горутине через recover, вызванный из отложенной функции; recover в другой горутине не поможет.
Горутины в Go предназначены для независимого выполнения функций внутри одного процесса, поэтому ошибка одной из них потенциально может нарушить состояние всей программы. Механизм panic позволяет немедленно сигнализировать о невосстановимой ошибке, а defer и recover дают возможность явно определить границу, на которой приложение пытается изолировать сбой.
Такой подход решает проблему скрытого продолжения работы после нарушения инвариантов. При этом Go не перезапускает завершившуюся из-за паники горутину автоматически.
Если рабочая горутина вызывает panic и никто не выполняет корректный recover, runtime начинает раскручивать стек этой горутины, выполняет её отложенные функции, выводит диагностическую информацию и завершает процесс.
Это опасно для серверов, обработчиков очередей и фоновых задач: одна ошибка может остановить все остальные горутины. Попытка поставить recover в main или в другой горутине не защищает от паники рабочего потока, потому что состояние паники локально для конкретной горутины.
recover работает только внутри отложенной функции, выполняющейся в той же горутине, где возникла паника. После успешного восстановления функция, в которой произошла паника, не продолжает выполнение с места сбоя; её выполнение завершается после обработки отложенных функций.
Типичный изолирующий слой располагают на границе запуска фоновой задачи:
Здесь recover выполняется в той же горутине, поэтому паника не завершает процесс. Канал done нужен только для ожидания окончания воркера; он не перехватывает панику и не заменяет recover.
Перехватывать следует только на осмысленной границе: например, в общем обёрточном коде обработчика или воркера. После восстановления обычно требуется записать стек и контекст ошибки, отправить метрику, отменить связанную работу или перезапустить задачу. Без диагностики recover может скрыть программную ошибку и оставить приложение в некорректном состоянии.
Важно отличать обычную панику от фатальных ошибок runtime. Некоторые ошибки, например конкурентная запись в карту, могут завершить процесс без возможности надёжно восстановиться через recover. Кроме того, recover не делает доступ к общим данным безопасным и не устраняет причину гонки или нарушения инварианта.
Сервис обрабатывает задания из очереди в нескольких горутинах. Один обработчик получает неожиданные данные и вызывает панику.
Вариант без защиты прост, но одна ошибка останавливает весь процесс. Вариант с recover внутри каждой бизнес-функции локализует сбой, однако засоряет код и может скрыть ошибки. Вариант с одной обёрткой вокруг каждой запускаемой горутины централизует обработку, но требует заранее определить, можно ли безопасно продолжить работу после сбоя.
Практичным решением будет обёртка на границе воркера: она фиксирует панику вместе со стеком, помечает задание как ошибочное, освобождает ресурсы и при необходимости запускает новый воркер. Если паника указывает на возможное повреждение критического состояния, безопаснее завершить процесс и передать перезапуск внешнему менеджеру, чем продолжать работу в сомнительном состоянии.
recover в main, если паника возникла в рабочей горутине?Нет. Паника и механизм её восстановления привязаны к стеку конкретной горутины. recover в main может обработать панику только при её возникновении в самом main или в вызываемом им стеке, но не в параллельно работающей горутине.
recover сработал?Нет. После выполнения отложенной функции с успешным recover функция, в которой произошла паника, завершается. Поэтому восстановление не означает возврат к следующей инструкции; необходимы явный возврат, передача ошибки или завершение текущей задачи.
recover, что приложение после паники осталось корректным?Нет. recover только предотвращает распространение конкретной паники до завершения процесса. К моменту сбоя могли измениться общие данные, остаться частично выполненная операция или нарушиться состояние внешней транзакции, поэтому после восстановления нужно оценить состояние задачи и выбрать: повторить её, отменить, изолировать или завершить процесс.