[Go] Concurrency: 고루틴 내에서의 에러 핸들링

만약 고루틴에서 에러가 발생하면 어떻게 처리해야 할까?

정말 단순하게 생각한다면 그냥 아래와 같은 형태로

오류를 출력하는 간단한 형태로 넘어가고 싶을 수도 있다.

하지만 이래서는 안된다. 이건 이도저도 아닌 코드일 뿐이다.

이런 상황에서의 Best Practice는, 함수에서 튜플 리턴으로 에러를 전파하듯이, 채널로 에러를 전파해주는 것이다.

먼저 실제 값과 에러의 튜플을 감싸주는 구조체를 정의한다.

꼭 제너릭일 필요는 없지만, 위와 같이 제너릭으로 한번 만들고 돌려쓰면 편할 것이다.

그리고 비동기 함수에서는 해당 모나드의 채널을 반환한다.

그러면 성공했을 때는 값 형태로 값을 쏘고, 실패했을 때는 에러를 쏘는 식으로 유연하게 대응을 할 수 있다.


이후에는 받는 측에서 잘 핸들링하면 된다.


어렵지 않다.

전체 코드

package main

import (
	"fmt"
	"os"
)

type Result[T any] struct {
	Err   error
	Value *T
}

func ReadFileAsync(filename string) chan Result[string] {
	result := make(chan Result[string])

	go func() {
		if data, err := os.ReadFile(filename); err == nil {
			stringData := string(data)

			result <- Result[string]{
				Value: &stringData,
			}
		} else {
			result <- Result[string]{
				Err: err,
			}
		}
	}()

	return result
}

func main() {
	result := <-ReadFileAsync("not_found.txt")

	if result.Err != nil {
		fmt.Println("Error:", result.Err)
	} else {
		fmt.Println("Value:", *result.Value)
	}
}