Go 언어에서 Cancel Context with Interrupt 제대로 이해하기

Golang

Go(Golang)는 병행 처리(concurrency)에 강력한 기능을 제공하는 언어입니다. 특히 context 패키지를 활용하면 작업 중 취소(cancel), 타임아웃(timeout), 마감 기한(deadline) 등을 깔끔하게 제어할 수 있습니다. 이번 글에서는 Go에서 흔히 쓰이는 패턴 중 하나인 “Cancel Context with Interrupt”, 즉 운영체제의 인터럽트 신호(Ctrl+C 등)를 감지하여 context를 취소하는 방법에 대해 설명드리겠습니다.


왜 Context와 Interrupt를 함께 써야 할까?

운영 환경에서 Go 애플리케이션은 다음과 같은 상황에 직면할 수 있습니다:

  • 사용자가 Ctrl+C를 눌러 서버를 종료하려는 경우
  • 쿠버네티스(kubernetes)가 Pod를 종료하는 시그널을 보낸 경우
  • 작업 도중에 타임아웃이 발생해 중단해야 하는 경우

이럴 때, 단순히 종료하는 것이 아니라 작업 중이던 goroutine이나 리소스를 안전하게 정리하고 싶다면 context와 os/signal을 함께 사용하는 패턴이 유용합니다.


기본 구조: context + os.Interrupt

Go에서는 os/signal 패키지를 통해 운영체제의 인터럽트 시그널을 감지할 수 있고, context.WithCancel()을 통해 수동으로 취소 가능한 컨텍스트를 만들 수 있습니다.

ctx, cancel := context.WithCancel(context.Background())

인터럽트가 들어오면 cancel() 함수를 호출하여 context를 종료할 수 있게 됩니다.


실제 코드 예제

package main

import (
"context"
"fmt"
"os"
"os/signal"
"time"
)

func main() {
// 취소 가능한 context 생성
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// 운영체제 시그널 수신 설정
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)

// 인터럽트 시 cancel() 실행
go func() {
<-sigChan
fmt.Println("인터럽트 시그널 수신! 종료합니다.")
cancel()
}()

// 백그라운드 작업 시작
go doWork(ctx)

// context가 종료될 때까지 대기
<-ctx.Done()
fmt.Println("메인 함수 종료")
}

func doWork(ctx context.Context) {
fmt.Println("작업을 시작합니다.")
for {
select {
case <-ctx.Done():
fmt.Println("작업이 취소되었습니다:", ctx.Err())
return
default:
fmt.Println("작업 진행 중...")
time.Sleep(1 * time.Second)
}
}
}

실행 흐름

  1. 프로그램 실행
  2. doWork goroutine이 무한 루프 작업 수행
  3. Ctrl+C 입력 시 os.Interrupt 시그널 감지 → cancel() 실행
  4. context 종료 → doWork 루틴이 ctx.Done()을 감지하고 종료
  5. 메인 함수도 <-ctx.Done()에 의해 종료

이 패턴을 써야 하는 이유

상황context + interrupt가 필요한 이유
CLI 도구 또는 서버 종료안전하게 리소스를 해제하고 로그를 남기기 위함
외부 API 호출 또는 DB 트랜잭션취소 가능한 요청을 통해 자원 낭비를 줄이기 위함
병렬 작업 중 취소 필요전체 작업 중 하나라도 실패하면 나머지도 취소 가능

WithTimeout, WithDeadline과 함께 쓰기

context.WithCancel() 외에도 context.WithTimeout()을 함께 사용하면 인터럽트와 타임아웃 두 가지 상황 모두에 대응할 수 있습니다:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

마무리

Go에서 Cancel Context with Interrupt는 매우 강력하고 실용적인 패턴입니다. 특히 시스템 종료나 유저 인터럽트에 반응해서 안정적인 종료 처리를 할 수 있는 점은 서버 개발이나 CLI 도구 등 다양한 영역에서 필수적인 기능입니다.

이 패턴을 익혀두시면 goroutine 처리, 자원 정리, 사용자 경험 모두 향상될 수 있습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤