프로그래밍백엔드 Go 개발자

Go에서 내장 컨텍스트 패키지는 어떻게 작동합니까? 무엇을 위해 사용되며, 컨텍스트를 올바르게 생성하고 종료하는 방법은 무엇입니까? 사용할 때 어떤 오류를 범할 수 있습니까?

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

답변

context 패키지는 goroutine 및 외부 호출(HTTP, DB) 작업 시 코드의 여러 부분 간의 생명주기 관리(취소, 타임아웃) 및 메타데이터 전달을 위한 표준입니다.

생성:

  • context.Background() — 루트 컨텍스트
  • context.WithCancel(parent) — 취소 가능한 새로운 컨텍스트
  • context.WithTimeout(parent, duration) — 타임아웃이 있는 컨텍스트
  • context.WithValue(parent, key, value) — 데이터가 포함된 컨텍스트

컨텍스트를 종료하는 것은 리소스를 올바르게 해제하기 위해 중요합니다. 예제:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // 이후 ctx는 goroutine/HTTP 요청에서 사용됩니다.

일반적인 패턴은 함수의 첫 번째 인수로 context를 전달하는 것입니다. 예:

func process(ctx context.Context) error { ... }

속임수 질문

context.TODO()와 context.Background()를 실제 컨텍스트 대신 언제 전달할 수 있고, 두 가지의 차이는 무엇입니까?

많은 사람들이 context.Background()를 자리 표시자로 사용하지만:

  • context.Background()는 트리의 뿌리이며, main() 및 테스트에서 초기화할 때만 사용해야 합니다.
  • context.TODO()는 어떤 컨텍스트를 사용해야 할지 불확실할 때 필요하며, 리팩토링 중 일시적인 "임시방편"으로 사용합니다. 프로덕션 코드에서는 TODO는 허용되지 않습니다: 무엇이 어디로 전달되는지 정확히 아는 것이 필요합니다.

주제에 대한 미숙지로 인한 실제 오류 예


이야기

마이크로서비스에서 context.WithTimeout()을 생성한 후 cancel()을 호출하는 것을 잊어버려 요청이 중단되고, 종료된 goroutine이 런타임에서 "걸려 있는" 타이머를 남겨 메모리 누수가 발생했습니다.


이야기

핸들러에서 요청에서 온 context 대신 context.Background()를 전달함으로써 모든 취소 및 trace-id 체인이 손실되어 타임아웃 제한이 작동하지 않고 요청 취소가 이루어지지 않았습니다.


이야기

context.WithValue()를 통해 개발자들이 데이터를 전달했지만, 키는 문자열이었습니다. 이로 인해 다양한 패키지에서 키의 충돌 가능성으로 인해 예상치 못한 오류가 발생했습니다 ("키가 이미 사용 중입니다"). 올바른 관행은 키에 대해 고유한 유형을 사용하는 것입니다.