프로그래밍Senior Go Developer

Go에서 내장 함수 recover와 panic을 어떻게 구현하는지 설명해주세요. goroutine에서 안전하게 복구하기 위한 올바른 순서는 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변

Go에서 팬릭(panic)은 프로그램의 치명적인 오류를 알리기 위해 사용됩니다. 팬릭이 호출되면 실행은 스택을 언와인드하고 모든 deferred 함수가 호출되는 과정부터 시작됩니다. 스택에 recover()를 호출하는 함수가 있다면, 이는 팬릭을 가로채고 처리할 수 있습니다. 그러나 recover는 오직 자신의 goroutine 내부에서만 작동하며 defer로부터 호출될 때만 유효합니다.

안전한 복구를 위한 권장 패턴:

func safe(fn func()) { defer func() { if r := recover(); r != nil { fmt.Println("팬릭에서 복구됨:", r) } }() fn() } go safe(func() { panic("실패!") // 프로그램이 중단되지 않음 })

다음 사항을 기억하는 것이 중요합니다:

  • panic은 첫 번째 recover까지 현재 goroutine의 실행을 종료합니다.
  • Recover는 같은 goroutine 내에서 defer로 호출될 때만 작동합니다.
  • Recover가 사용되지 않으면, 팬릭은 전체 프로그램을 종료시킵니다.

함정 질문

recover가 다른 goroutine에서 발생한 팬릭을 가로챌 수 있나요?

답변: 아닙니다, recover는 팬릭이 발생한 goroutine 내에서만 작동하며, 오직 defer 함수에서 호출된 경우에만 가로챌 수 있습니다. 팬릭이 한 goroutine에서 발생하고 recover가 다른 goroutine에서 호출되면, 가로채기가 이루어지지 않으며 프로그램은 비정상 종료됩니다.

예시:

func main() { go func() { panic("goroutine 내부") }() time.Sleep(time.Second) recover() // 작동하지 않음! Panic이 프로그램을 종료시킴 }

주제에 대한 모르고 지나친 실제 오류 사례


이야기

개발자가 메인 함수에서만 패턴 defer recover()를 사용하여 오류 처리를 구현했습니다. worker 내에서 팬릭이 발생했을 때, 전역 recover가 이를 가로채지 못해 전체 프로그램이 비정상 종료되었습니다.


이야기

프로젝트에서는 웹 서버의 유연한 종료를 위해 defer/recover를 사용하였으며, 이것이 충분하다고 생각했습니다. 그러나 한 goroutine에서 팬릭이 발생하였고, recover의 처리가 적절한 위치에 서지 않아 전체 프로세스가 종료되는 문제를 겪었고, 결과적으로 모든 워커 풀을 리팩토링해야 했습니다.


이야기

메시지 처리 흐름에서 사용자 함수의 잘못된 작동으로 팬릭이 발생했습니다. 개발자는 상위 수준의 recover가 이를 "잡아줄 것"이라고 예상했지만, recover가 오직 defer에서만 작동한다는 것을 인식하지 못했습니다. 이로 인해 서비스는 불규칙적으로 크래시되었고, 큐에 잘못된 메시지가 나타날 때마다 문제가 발생했습니다.