[GoLang] 시간 초과 로직 Context, 채널과 비교

2025. 2. 25. 15:09· Go Lang/Study
목차
  1. 개요
  2. 코드

개요

go의 context 기능은 go 커뮤니티에서도 논쟁이 많고 이야기가 여러 가지가 있습니다.

정리하면 주로 아래와 같죠

 

  • 작업 취소와 타임 아웃의 유용성 : 고루틴 작업에서의 취소와 타임아웃에서는 리소스 누수 방지와 응답 개선의 효과가 있음
  • 사용에 대한 어려움 : 초기 학습의 혼란과 올바른 패턴에 이해 필요
  • 매개변수 남용 우려 : context로 값을 전달하는 과정이 오히려 가독성을 해칠 수 있다
  • 로깅과 통합 : 고유 값을 context에 담아서 로깅에 사용, 매개변수 남용이 될 수 있음

동시성에서 필요하고 쓰기는 좋은 건 맞지만, 올바른 패턴의 필요성을 강조하고 있습니다.

남발하면 가독성을 그만큼 해쳐지기 때문이죠

 

저 같으 경우 아직 Context의 존재와 기능은 머리로는 알고 있습니다만

회사 소스 중에 어디에 적용하기가 애매해서 보류하고 있습니다.

 

그나마 적용하기 좋은 부분은 시간초과로 생각하고 있습니다.

이 부분이 Context의 기능 중에서 가장 직관적입니다.

코드

3초가 지나면 타임아웃이 울리는 로직에서 작업이 5초간 진행될 때를 가정한 코드입니다.

그걸 Context로 푼 코드죠

package main

import (
	"context"
	"fmt"
	"time"
)

func process() {
	// 3초 후 종료하는 컨텍스트
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	// 작업 수행
	err := doSomething(ctx)

	// 타임 아웃에 따른 에러 반환
	if err != nil {
		fmt.Println("Status Request Timeout")
	} else {
		// 정상 처리
		fmt.Println("Success")
	}
}

func doSomething(ctx context.Context) error {
	fmt.Println("Processing request...")

	select {
	// 5초 작업
	// select 문과 같이 사용해야지, 컨텍스트 취소를 감지 가능
	case <-time.After(5 * time.Second):
		fmt.Printf("Task completed successfully")
		return nil
	case <-ctx.Done(): // context 에 종료 신호가 올 경우
		fmt.Println("Task aborted due to timeout:", ctx.Err())
		return fmt.Errorf("Request Timeout")
	}
}

func main() {
	process()
}

이걸 실행하면 다음과 같이 context deadline으로 에러가 뜨면 원하던 바를 이룬 거죠

Processing request...
Task aborted due to timeout: context deadline exceeded
Status Request Timeout

이제 실제 서비스 로직에서도 데이터 처리를 하면서 응답이 길어질  때를 대처할 수 있게 되었습니다.

하지만 의문이 든 점은 채널로도 충분히 커버가 가능하다는 생각이 들었습니다.

 

아래는 같은 코드를 채널로 구현했을 때죠.

package main

import (
	"fmt"
	"time"
)

func process() {
	// 작업 완료 여부를 전달할 채널
	done := make(chan error)
	// 작업 수행
	go doSomething(done)
	// 타입 아웃 채널
	timeOut := time.After(3 * time.Second)

	select {
	case err := <-done: // 작업 완료
		if err != nil {
			fmt.Println("Status Request Timeout")
		} else {
			fmt.Println("Success")
		}
	case <-timeOut: // 3초 후 타임아웃
		fmt.Println("Status Request Timeout")
	}
}

func doSomething(done chan<- error) {
	fmt.Println("Processing request...")
	select {
	case <-time.After(5 * time.Second): // 5초 걸리는 작업
		fmt.Println("Task completed successfully")
		done <- nil // 작업 성공 신호 전송
	}
}

func main() {
	process()
}

결과는 아래와 같죠

Processing request...
Status Request Timeout

context 에러를 찍는 부분이 사려져서 결과가 살짝 다르지만, 같은 로직을 구현했습니다.

채널로도 충분히 비슷한 기능을 구현할 수 있지만, 아래 사항들을 직접 구현해야 했네요

  • 채널로 취소 전파 구현
  • 채널 동기화 구현, 확장 시 계속 동기화 로직이 추가됨
  • 채널의 값을 직접 핸들링해야 함

확실히 다소 귀찮아 짐을 알 수 있습니다.

Context와 Channel의 차이를 표로 하면 다음과 같죠

  context.Context 사용 channel 사용
코드 복잡도 ✅ 간단 (ctx.Done()) ❌ 타이머, 채널 직접 관리 필요
취소 전파 ✅ 자동 ❌ 직접 채널로 취소 구현
타임아웃 처리 ✅ WithTimeout 사용 ❌ time.After로 직접 설정
확장성 ✅ 부모-자식 컨텍스트 활용 가능 ❌ 추가적인 채널 동기화 필요

 

확실히 취소 전파, 타임아웃, 확장이나, 매개변수를 담을 수 있다는 점 등

context의 기능이 다채롭다 보니 잘하면 잘 쓸 수 있을 것 같습니다.

 

당장 적용시켜 볼 분야는 로깅과 시간초과 등이 있겠군요

다른 분의 예제를 볼 때는 grpc에서 데이터를 받으면 이를 context로 핸들링해서 관련 함수 및 키-저장 변수를 사용하더군요

 

그리고 컨텍스트를 까보면 채널과 인터페이스를 구현된거라, 채널과 인터페이스로 대체가 가능한건 어찌보면 당연한거네요

하지만 Context를 사용함으로써 값의 저장소의 생명 주기(맥락)를 관리한다.

그래서 맥락이라고 하는 것 같군요.

 

※ gin에 있는 Context는 이것과 달리, request 핸들링에 특화된 다른 기능입니다 (타 언어의 context 형태)

이 부분이 재밌네요. 정확히는 다른 기능을 하는데, 키워드는 같다는 점이 상당히 마음에 안드네요. ※

 

추가로 Context의 deadline과 timeout을 비교했을 때 deadline의 쓰임새가 붕 뜨는 느낌이었는데

생각해보니 은행권같이 11시 55분부터 점검을 해야해서 모든 요청을 막아야할 때 이럴 때는 deadline이 용이하네

반응형

'Go Lang > Study' 카테고리의 다른 글

[GoLang] gRPC 통신 패턴  (0) 2025.03.21
[GoLang] REST API, gRPC 비교  (0) 2025.03.15
[GoLang] net/http에서 http 요청을 동시적으로 처리하는 이유  (0) 2025.02.17
[GoLang] GC 튜닝 Profiling  (0) 2025.02.05
[GoLang] Garbage Collector 개념  (0) 2025.01.29
  1. 개요
  2. 코드
'Go Lang/Study' 카테고리의 다른 글
  • [GoLang] gRPC 통신 패턴
  • [GoLang] REST API, gRPC 비교
  • [GoLang] net/http에서 http 요청을 동시적으로 처리하는 이유
  • [GoLang] GC 튜닝 Profiling
DSeung
DSeung
DSeung
Dev log
DSeung
  • 분류 전체보기 (193)
    • PHP (62)
      • Laravel (31)
      • Error (5)
      • Setting (11)
      • Modern PHP (15)
    • Go Lang (51)
      • Study (30)
      • Algorithm (17)
      • Setting (1)
      • Error (3)
    • Java (11)
      • Spring (3)
      • JSP (0)
      • Error (2)
      • Setting (2)
      • 단축키 (2)
    • JavaScript (6)
      • Modern JavaScript (4)
      • Node (1)
    • Android Kotlin (5)
      • Study (4)
      • Error (1)
    • 컴퓨팅 기술 (12)
      • 데이터베이스시스템 (4)
      • Docker (2)
      • 크롤링 & 스크래핑 (1)
      • API (1)
      • 클라우드 (1)
      • 네트워크 (1)
    • MySQL (7)
    • AWS (1)
    • Git (5)
      • GItLab (1)
      • GitHub (4)
    • 도메인 (2)
      • 안과 (2)
    • 자격증 (7)
      • SQLD (1)
      • 정보처리기사 (6)
    • Mac os (1)
    • 나머지 (13)
      • tistory (1)
      • 기타 (9)
      • 일기 (3)
    • 독서 (10)

인기 글

최근 글

블로그 메뉴

  • 홈
  • 태그
전체
오늘
어제
hELLO · Designed By 정상우.v4.2.0
DSeung
[GoLang] 시간 초과 로직 Context, 채널과 비교
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.