아무리 잘 짜여진 코드에서도 에러는 발생하기 마련이다. 그 원인이 내부적인 문제가 아니라 외부 환경에 의한 문제일 수 도 있고 아직 내가 겪어보지 못한 다양한 이유가 존재할 수 있다. 그렇기에 안정적인 서비스를 위해선 효율적인 에러 처리가 필수적이다. 그리고 Go라는 언어는 다른 언어에서 채용하는 에러 처리방법인 예외 모델을 사용하지 않고 더욱 직접적으로 에러를 다루는 형식을 채용한다. 그렇기에 다른 프로그래밍 언어에 비해 귀찮지만 조금 더 효율적이고 직관적인 에러 처리를 할 수 있다.
그렇다면 동시성 프로그래밍을 적용한 작업에선 어떤식으로 처리하는 것이 좋을까?
에러 처리에서 중요한 것
에러 처리를 함에 있어서 가장 중요한 것은 에러를 처리하는 주체이다. 동시에 프로세스가 병렬적으로 진행되는 동시성 프로그래밍의 경우 프로세스마다 에러를 각자 처리한다면 개발자가 에러에 대응하기 곤란한 상황을 마주칠 수 있다.
Bad Example
func BadExam() {
checkStatus := func(done <-chan any, urls []string) <-chan *http.Response {
responses := make(chan *http.Response)
go func() {
defer close(responses)
for _, url := range urls {
resp, err := http.Get(url)
//고루틴 내부에서 에러 처리
if err != nil {
fmt.Println(err)
continue
}
select {
case <-done:
return
case responses <- resp:
}
}
}()
return responses
}
done := make(chan any)
defer close(done)
urls := []string{"https://www.google.com", "https://badhost"}
for response := range checkStatus(done, urls) {
fmt.Printf("Response: %v\n", response.Status)
}
}
고루틴 내부에서 에러를 처리하는 모습이다. 이렇게 고루틴 내부에서 에러를 처리한다면 고루틴은 할 수 있는 것이 많이 없다. 나 에러 나서 죽어요.. 말하는 것 밖에는 ㅠ
Good Example
func Exam() {
type Result struct {
Error error
Response *http.Response
}
checkStatus := func(done <-chan any, urls ...string) <-chan Result {
results := make(chan Result)
go func() {
defer close(results)
for _, url := range urls {
var result Result
resp, err := http.Get(url)
result = Result{Error: err, Response: resp}
select {
case <-done:
return
case results <- result:
}
}
}()
return results
}
done := make(chan any)
defer close(done)
urls := []string{"https://www.google.com", "https://badhost"}
for result := range checkStatus(done, urls...) {
// main 함수에서 에러 처리
if result.Error != nil {
fmt.Printf("error: %v\n", result.Error)
continue
}
fmt.Printf("Response: %v\n", result.Response.Status)
}
}
고루틴을 생성한 메인 함수에서 에러를 넘겨받아 처리하는 모습이다. 현재 코드에서는 단순히 위 BadExample과 같이 에러를 출력하는데 미치는 처리를 하였지만 개발자가 에러를 발생시킨 프로세스에 대한 더 많은 컨텍스트를 알고 있는 만큼 에러에 대한 더욱 적절한 조치를 취할 수 있게 된다.
O'Reilly에서 출판한 Concurrency in Go를 참고하여 작성한 글입니다.
본인의 공부를 위한 포스팅이며 틀린 부분이 있을 수 있습니다. 만일 틀린 부분을 발견한다면 말씀해 주시면 감사하겠습니다.
'Study > Go' 카테고리의 다른 글
[Go] GC(Garbage Collection) 심화 (0) | 2022.08.05 |
---|---|
[Go] 고루틴(GoRoutine) 심화(7) - 파이프라인 (0) | 2022.06.24 |
[Go] 고루틴(GoRoutine) 심화(5) - 누수 관리 (0) | 2022.05.24 |
[Go] 고루틴(GoRoutine) 심화(4) - channel (0) | 2022.05.15 |
[Go] 고루틴(GoRoutine) 심화(3) - sync.Pool (0) | 2022.05.13 |