진행 중인 작업 취소하기

진행 중인 작업 취소하기

진행 중인 작업은 Go의 context.Context로 관리할 수 있습니다. Context는 그것이 나타내는 전체 작업이 취소되어 더 이상 필요 없게 되었는지를 알려 주는 표준 Go 데이터 값이에요. context.Context를 함수 호출과 서비스 사이에 넘겨주면, 처리 결과가 더 이상 필요 없을 때 그것들이 일찍 작업을 멈추고 오류를 반환할 수 있습니다. Go 개발자를 위한 많은 API가 Context 인수를 받는 메서드를 제공해서, 애플리케이션 전체에 걸쳐 Context를 쓰기 쉽게 만들어 줍니다.

출처: Go 공식 문서

타임아웃 후 데이터베이스 작업 취소하기

Context를 쓰면 일정 시간이나 데드라인이 지난 뒤 작업을 취소하도록 만들 수 있어요. 타임아웃이나 데드라인이 있는 Context를 만들려면 context.WithTimeout이나 context.WithDeadline을 호출하면 됩니다. 아래 타임아웃 예제의 코드는 Context를 만들어 sql.DBQueryContext 메서드에 넘겨줍니다.

func QueryWithTimeout(ctx context.Context) {
    // Create a Context with a timeout.
    queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    // Pass the timeout Context with a query.
    rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    // Handle returned rows.
}

여기서 queryCtxctx에서 파생된 것처럼, 한 context가 바깥 context에서 파생되면 바깥 context가 취소될 때 파생된 context도 자동으로 취소됩니다. 예를 들어 HTTP 서버에서 http.Request.Context 메서드는 그 요청과 연관된 context를 반환합니다. HTTP 클라이언트가 연결을 끊거나(HTTP/2에서 가능) HTTP 요청을 취소하면 그 context가 취소되는 거죠. 위 QueryWithTimeout에 HTTP 요청의 context를 넘기면, 전체 HTTP 요청이 취소되거나 쿼리가 5초 이상 걸리면 데이터베이스 쿼리가 일찍 멈추게 됩니다.

참고: 타임아웃이나 데드라인으로 새 Context를 만들 때 반환되는 cancel 함수 호출은 항상 defer로 걸어 두세요. 그러면 포함하는 함수가 끝날 때 새 Context가 쥔 리소스가 해제됩니다. 그것은 queryCtx도 취소하지만, 함수가 반환될 즈음엔 더 이상 아무도 queryCtx를 쓰지 않으니 괜찮아요.

더 알아보기 (Learn more)

  • context 패키지의 전체 API는 표준 라이브러리 문서를 확인하세요.
  • Go 동시성 패턴에서 Context의 활용은 "Go Concurrency Patterns: Context" 글을 참고하세요.
  • 데이터베이스 작업에서 타임아웃과 관련된 다른 패턴은 context 패키지와 database/sql 패키지 문서를 보세요.