Go 1.20에서 추가된 에러 처리 개선 사항
배경
마이크로서비스 간 통신 로직을 작성하다가 여러 서비스의 에러를 동시에 수집해야 하는 상황이 생겼다. 기존에는 직접 구조체를 만들어 처리했는데, Go 1.20에서 이를 표준 라이브러리로 지원한다는 소식을 접했다.
errors.Join 사용
여러 에러를 하나로 합칠 수 있게 되었다.
err1 := fetchUserService()
err2 := fetchOrderService()
err3 := fetchInventoryService()
if err := errors.Join(err1, err2, err3); err != nil {
log.Printf("multiple services failed: %v", err)
return err
}
fmt.Errorf의 다중 wrapping
%w를 여러 번 사용할 수 있게 되었다.
if err1 != nil && err2 != nil {
return fmt.Errorf("failed: %w and %w", err1, err2)
}
errors.Is, errors.As 동작
errors.Join으로 합쳐진 에러는 errors.Is와 errors.As로 개별 에러를 확인할 수 있다.
err := errors.Join(io.EOF, context.Canceled)
if errors.Is(err, io.EOF) {
// true
}
if errors.Is(err, context.Canceled) {
// true
}
실제 적용 사례
배치 작업에서 일부 실패가 있어도 전체를 중단하지 않고, 마지막에 모든 에러를 반환하는 패턴에 적용했다.
var errs []error
for _, item := range items {
if err := processItem(item); err != nil {
errs = append(errs, err)
continue
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
기존에 직접 구현했던 multierror 타입을 제거하고 표준 라이브러리로 대체할 수 있었다. 코드가 간결해지고 팀원들도 이해하기 쉬워졌다.