정글에서 온 개발자
1/19 TIL 내가 몰랐던 Go 웹 서버 개발시 코드 패턴 본문
Context
엔드포인트 내부에서 클라이언트 통신 단절이나 타임아웃 등을 context.Context만 알 수 있다.
중단 처리를 감지하지 못하면, 요청이 타임아웃 됐지만 처리를 계속 하거나, 서버를 정지하고자 중단 처리를 실행해도 요청 처리가 중돤되지 않아 서버 프로세스가 종료되는 순간까지 처리를 계속하게 된다.
net/http 패키지의 *http.RequestContext 메서드에서 얻는 context.Context 타입값을 사용한다.
fiber에는 *fiber.Ctx 의 .Context() 메서드를 이용해 가져올 수 있다.
<-ctx.Done()을 이용한 트랜잭션 롤백 코드를 따로 짜야할 것 같지만, database/sql 패키지도 ctx를 이용하고 있어 해당 ctx를 잘 전달했다면 Rollback도 알아서 된다!
gorm에서는 다음처럼 시작하면 된다.
tx := db.WithContext(ctx).Begin()
이를 위해서 호출하는 메서드의 맨 앞에 ctx를 넘겨주는 패턴을 쓰는 것이 좋다.
주의할 점은 ctx를 다른 구조체에 담아서 보내지 말라는 것이다.
또 ctx에 메타데이터를 실어 보낼 수도 있는데, 여기에 credential 같은 비즈니스 로직과 분리되서 관리될 수 있는 정보는 보내도 좋지만 비즈니스 로직과 관련된 DTO등은 안 보내는 것이 좋다. 가독성을 해칠 수 있기 때문이다.
https://go.dev/wiki/CodeReviewComments#contexts
그런데, 둘러보는 웹 어플리케이션 프로젝트들에서 잘 사용하고 있지는 않은 것 같다.
Rollback
defer 문으로 한번에 호출하는 게 좋다. err마다 일일히 호출하면 잊어버릴 수도 있기 때문이다.
commit 이후에 rollback이 실행되는 게 걱정되지만, database/sql 패키지의 Rollback 메서드는 Commit 메서드나 context 패키지 경유의 중단 처리가 끝난 트랜잭션에 대해서는 RDBMS의 롤백 처리를 실행하지 않는다.
종합적으로는 다음 코드를 쓰면 좋겠다.
func (r *Repository) Update(ctx context.Context) error{
tx,err:= r.db.WithContext(ctx).Begin()
if err != nil {
return err
}
defer tx.Rollback()
-, err := tx. ...
if err != nil {
return err
}
...
return tx.Commit()
}
'TIL' 카테고리의 다른 글
1/20 TIL 이 쿼리가 왜 빨라졌을까? (0) | 2025.01.20 |
---|---|
Go 웹 API swagger로 문서화 패키지 고르기 (0) | 2025.01.20 |
Go가 빌드 시간 문제를 해결한 방법 (0) | 2025.01.19 |
Go가 탄생한 이유 (0) | 2025.01.19 |
1/15 TIL 단위 테스트 안티패턴 (0) | 2025.01.16 |