Go 언어에서 Timeout context with interrupt 제대로 이해하기

Golang

Go 언어를 사용하다 보면 “작업을 일정 시간 동안만 실행하다가 중단하고 싶다”, 또는 “사용자가 Ctrl+C를 눌렀을 때 우아하게 종료하고 싶다”는 상황이 자주 발생합니다. 예를 들어 웹 서버에서 API 요청에 시간이 너무 오래 걸리면 중단하거나, 백그라운드 작업 도중에 프로그램을 강제 종료하는 상황 등입니다.

이럴 때 유용하게 쓰이는 Go의 기능이 바로 context.WithTimeoutos/signal입니다.

이번 글에서는 이 두 가지를 조합하여 Timeout context with interrupt를 Go 다운 방식으로 제대로 사용하는 방법을 소개합니다.


개념 정리: 무엇을 위한 기능인가?

✅ context.WithTimeout()

  • 일정 시간이 지나면 자동으로 취소되는 context를 생성합니다.
  • 네트워크 요청, DB 작업 등에 널리 사용됩니다.

✅ os/signal.Notify()

  • 운영체제에서 보내는 시그널(예: SIGINTSIGTERMCtrl+C)을 감지합니다.
  • 사용자가 프로그램을 강제 종료하려는 신호를 포착할 수 있습니다.

이 조합이 왜 강력한가?

두 기능을 조합하면 다음과 같은 장점이 있습니다:

  • 사용자 인터럽트(Ctrl+C)와 타임아웃 모두에 대응 가능
  • 하나의 cancel()로 모든 goroutine을 깔끔하게 중단
  • 리소스 정리(예: 파일 닫기, DB 연결 종료 등)를 안전하게 처리 가능

실전 예제: Timeout + Interrupt 처리하기

package main

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

func main() {
// 5초 타임아웃 설정
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// 인터럽트 감지 채널 생성
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)

// 인터럽트 발생 시 context 취소
go func() {
<-sigChan
fmt.Println("\n인터럽트 시그널 감지! 취소 신호 보냅니다.")
cancel()
}()

// 작업 수행
fmt.Println("작업을 시작합니다. 최대 5초 동안 실행됩니다.")
select {
case <-time.After(10 * time.Second): // 실제 작업 (10초 걸리는 작업이라고 가정)
fmt.Println("작업 완료!")
case <-ctx.Done():
fmt.Println("작업 취소됨:", ctx.Err())
}

fmt.Println("프로그램 종료")
}

결과 예시

  • 프로그램을 실행하고 5초를 넘기면:CopyEdit작업 취소됨: context deadline exceeded 프로그램 종료
  • 실행 도중에 Ctrl+C를 누르면:CopyEdit인터럽트 시그널 감지! 취소 신호 보냅니다. 작업 취소됨: context canceled 프로그램 종료

실무에서의 활용 예시

상황이 패턴을 적용하는 이유
API 요청이 너무 오래 걸릴 때클라이언트 타임아웃 설정
사용자 작업 중 Ctrl+C 누른 경우graceful shutdown 처리
CLI 도구 실행 중 타임아웃 제한 필요자동 중단 처리
외부 서비스 호출 시 리스크 관리응답 없는 호출 방지

흔한 실수

  • defer cancel()을 빼먹고 리소스 누수
  • ctx.Done()을 고루틴 내부에서 체크하지 않음
  • 시그널 채널을 버퍼 없이 생성하여 시그널 누락 발생

Tipsignal.Notify(sigChan, os.Interrupt) 이후 defer signal.Stop(sigChan)도 해주면 좋습니다.


마무리: Go다운 종료 방식

Go 언어의 철학은 단순하면서도 강력한 병행성 모델입니다. context와 os/signal을 조합하는 이 패턴은 실제 서비스 환경에서 가장 많이 사용되는 안전한 종료 처리 방식 중 하나입니다.

단일 cancel() 호출만으로 타임아웃과 인터럽트 두 가지 상황을 모두 커버할 수 있다는 점에서 매우 유용하고, 코드도 깔끔하게 유지할 수 있습니다.


📌 요약 정리

  • context.WithTimeout() → 일정 시간 후 자동 취소
  • os/signal.Notify() → Ctrl+C 등 시스템 시그널 감지
  • cancel() → 전체 작업을 종료할 수 있는 제어 지점
  • ctx.Done() → 모든 goroutine이 종료 조건을 감지하는 기준

댓글 달기

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

위로 스크롤