Go 1.7에서 context 패키지가 드디어 표준 라이브러리로 올라왔다. 기존 golang.org/x/net/context 쓰던 코드 갈아치우는중. 이제 net/http, database/sql도 context 받는 함수 시그니처가 표준으로 생김.
package main
import (
"context"
"database/sql"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
var name string
err := db.QueryRowContext(ctx,
"SELECT name FROM user WHERE id = ?", 42).Scan(&name)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Write([]byte(name))
}
HTTP 요청 컨텍스트에 2초 타임아웃 걸고 DB 쿼리로 내려보냄. 핸들러가 타임아웃되면 DB 쿼리도 자동 취소됨 (드라이버가 지원하는 경우). 이 전파가 자동이라 너무 편함.
패턴:
- handler 최상단에서
r.Context()로 시작 - 필요시
WithTimeout,WithCancel로 감쌈 - 다운스트림 (DB, 외부 API) 호출에 계속 전달
- goroutine 띄우면 반드시 ctx.Done() 체크 루프
context.Value에 요청 ID나 로깅용 메타 넣는것도 유용. 단 context.Value에 너무 많이 의존하면 안티패턴. 진짜 "요청 전체에 흐르는 값" 만 담아야 함. 비즈니스 로직 파라미터를 context에 숨기는건 나쁨.
기존 코드 마이그레이션은 간단함:
// before import "golang.org/x/net/context" // after import "context"
x/net/context와 표준 context는 type 호환됨 (전자는 후자의 type alias 수준). 기존 서드파티 라이브러리가 x/net/context 받아도 표준 context 넘기면 그대로 됨.
Go 1.5때 GC 스톱타임 줄인 것도 체감 컸는데, 1.7은 context 표준화가 가장 크다. 이거 없이 프로덕션 서버 못 쓰겠다.
댓글 없음:
댓글 쓰기