본문 바로가기
Study/Go

[Go] Context 패키지 알고쓰기

by _royJang 2022. 8. 17.

context를 공부하는 이유

git hub에서 Go를 사용하는 잘 짜여진 프로젝트들은 context를 잘 사용한다. 프로젝트에 엮인 micro service가 많아지면 많아질수록 더 효율적인 스킬처럼 느껴지며 context를 사용하는 부분을 미리 익혀두면 도움이 될 듯 하다.

 

 

context란?

context. 사전적 뜻은 “문맥”이다. 그리고 문맥의 정의는

naver 사전

프로세스 진행 중, 프로세스의 앞 뒤 간 맥락이라 표현할 수 있겠다.

Go에서 사용되는 context 또한 크게 다르지 않다. Context는 작업 명세서와 같은 역할로 프로젝트의 앞뒤 흐름을 관찰하고 제어할 수 있게 도와준다.


context를 사용하는 이유

 context는 다음 작업의 매개변수로 보낼 context를 위해 자식 context를 생성한다. 생성된 자식 context는 다음 작업의 매개변수로 보내지는 식으로 파생되며 트리 형태로 관리된다. 만일 한 context의 Cancel() 함수가 호출되면 그 함수가 가진 Done 채널이 닫히고 그 context의 자식 context를 가진 작업들의 진행을 중단시킬 수 있다.

 

간단한 예시를 들어보자.

A는 OO 뱅크의 애플리케이션에서 최근 10년간의 이체 목록 데이터를 요청했다. 하지만 시간이 너무 오래 걸려 A는 애플리케이션을 종료해버렸다. OO 뱅크의 서버는 이 요청자료를 DB에서 조회하여 가져오고 이 데이터들을 열심히 가공하고 있다. 하지만 A는 이미 애플리케이션을 종료한 지 오래다. 서버는 괜히 본인의 서버 자원을 소모한 것이다.

이런 경우에 context를 사용한다면 A가 애플리케이션을 종료 했을 때 서버의 작업을 중단시킬 수 있다.

즉, context는 프로젝트의 진행을 제어하는 역할을 할 수 있다.


context 구조

context는 Context interface와 이를 구현한 구현체인 emptyCtx, cancelCtx를 가진다.

// Context의 Interface
type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}
	Err() error
	Value(key any) any
}

// Context Interface의 구현체
type emptyCtx int

// Context Interface의 구현체
type cancelCtx struct {
	Context

	mu       sync.Mutex            
	done     atomic.Value          
	children map[canceler]struct{} 
	err      error                 
}

go의 context package에 직접 들어가 보면 주석을 통한 자세한 설명과 사용 예시 및 테스트 코드를 볼 수 있다.


Context 별 사용 목적 및 방법

앞에서 context는 두 가지 구현체가 구현돼 있는 것을 보였다. 이 구현체를 사용한 context들의 목적과 사용 방법을 살펴보겠다.

emptyCtx

생성

ctxBackground := context.Background()
ctxTODO := context.TODO() 

사용 목적 및 방법

Background(), TODO() 함수가 반환하는 값의 타입은 같다. 즉, 같은 행동을 할 수 있는 값을 반환한다.

하지만 이들은 흐름을 제어할 수 있는 능력이 없다. Context interface를 구현한 함수 들도 오직 nil 값을 반환한다. 하지만 두 함수의 사용 목적에는 차이가 있다.

  • Background()
    • 주로 main 함수나 init 함수와 같은 최상의 요청을 받는 곳에서 사용된다.
  • TODO()
    • Context의 목적이 명확하지 못할 경우 사용한다.

❗️Context를 매개변수로 받는 함수에게 Context 값을 nil로 보내는 것은 안된다. 이와 같은 경우에 context.TODO()를 사용하자

cancelCtx

생성

ctxWithCancel, cancel := context.WithCancel(context.Background())
ctxWithDeadline, cancel := context.WithDeadline(context.Background(), TIME)
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), TIME)

사용 목적 및 방법

emptyCtx와 달리 cancel이라는 값을 반환받는 것을 볼 수 있다. 이 cancel이라는 것은 함수이다. 1급 함수를 가지는 go 이기에 cancel 변수에 함수를 받을 수 있다.

cancel에 담기는 함수는 cancelCtx 구조체가 가지는 children map[canceler]struct{} 에 저장된 자식 context들을 모두 취소하는 역할을 한다.

기본적 사용 방법은 모두 같다. 하지만 함수 이름에서 볼 수 있듯 각자의 목적이 다르다.

  • WithCancel()
    • cancel이 호출될 시
  • WithDeadline
    • cancel이 호출될 시
    • 작업을 마치지 못하고 입력한 TIME이 됐을 시
  • WithTimeout
    • cancel이 호출될 시
    • 작업을 마치지 못하고 입력한 TIME의 시간이 지났을 시

 


참조

https://yoongrammer.tistory.com/35

https://devjin-blog.com/golang-context/