Don't Panic: Errgroup 고루틴에서 패닉 잡기
13117 단어 go
Nicosmos의 이미지, 퍼블릭 도메인, Wikimedia Commons를 통해
TL;DR 버전
StevenACoffman/errgroup은 Go의 훌륭함
sync/errgroup
에 대한 드롭인 대안이지만 고루틴 패닉을 오류로 변환합니다.이것을 원하는 이유
net/http
는 각 요청 제공 고루틴과 함께 패닉 핸들러를 설치하지만,고루틴은 부모 고루틴에서 패닉 핸들러를 상속하지 않으며 상속할 수도 없습니다.
따라서 하위 고루틴 중 하나에 있는
panic()
는 전체 프로그램을 종료합니다.따라서 프로덕션에서
sync.errgroup
를 사용할 때마다지연
recover()
하여 모든 새 고루틴의 시작 부분으로 이동하고 모든 패닉을 오류로 전환합니다. defer func() {
if rec := recover(); rec != nil {
err = FromPanicValue(rec)
}
}()
action in the Go Playground here에서 확인할 수 있습니다. 또한 스택 추적을 잃지 않도록 주의해야 합니다. 여기서 사용한
CollectStack
함수는 지나치게 단순화되어 FromPanicValue
및 CollectStack
프레임을 건너뛰지 않기 때문에 약간의 노이즈가 추가됩니다. 🤷♂️func FromPanicValue(i interface{}) error {
switch value := i.(type) {
case nil:
return nil
case string:
return fmt.Errorf("panic: %v\n%s", value, CollectStack())
case error:
return fmt.Errorf("panic in errgroup goroutine %w\n%s", value, CollectStack())
default:
return fmt.Errorf("unknown panic: %+v\n%s", value, CollectStack())
}
}
func CollectStack() []byte {
buf := make([]byte, 64<<10)
buf = buf[:runtime.Stack(buf, false)]
return buf
}
광산 동료Ben Kraft의 동료는 상용구(및 필요한 규율)를 피하기 위해 편리한 래퍼 코드
sync/errgroup
를 작성했습니다. 그의 허락을 받아 나lightly modified it는보다 일반적인 Go 커뮤니티를 위해 개인 작업 저장소에서 가져옵니다.
StevenACoffman/errgroup
는 Go의 훌륭한 대안입니다.sync/errgroup
고루틴 패닉을 오류로 변환한다는 차이점이 있습니다.see it in use in the playground 또는 여기에서 할 수 있습니다.
package main
import (
"fmt"
"github.com/StevenACoffman/errgroup"
)
func main() {
g := new(errgroup.Group)
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for i := range urls {
// Launch a goroutine to fetch the URL.
i := i // https://golang.org/doc/faq#closures_and_goroutines
g.Go(func() error {
// deliberate index out of bounds triggered
fmt.Println("Fetching:", i, urls[i+1])
return nil
})
}
// Wait for all HTTP fetches to complete.
err := g.Wait()
if err == nil {
fmt.Println("Successfully fetched all URLs.")
} else {
fmt.Println(err)
}
}
대위법
대안적인 견해를 가진 an interesting discussion이 있습니다.
몇 가지 예외를 제외하고 패닉이 발생하면 프로그램이 중단됩니다. 개발 및 테스트에서는 괜찮지만 밤에는 푹 자고 싶습니다.
선행 기술
대략적인 검색만으로 몇 가지 기존 오픈 소스 예제를 찾았습니다.
Kratos errgroup
마이크로서비스용 Kratos Go 프레임워크는 유사합니다errgroup.
해결책.
PanicGroup 세르게이 알렉산드로비치
기사Errors in Go:
From denial to acceptance에서 ,
(패닉 기반 흐름 제어를 옹호합니다 😱), 대략적으로 동일한
PanicGroup
가 있습니다.type PanicGroup struct {
wg sync.WaitGroup
errOnce sync.Once
err error
}
func (g *PanicGroup) Wait() error {
g.wg.Wait()
return g.err
}
func (g *PanicGroup) Go(f func()) {
g.wg.Add(1)
go func() {
defer g.wg.Done()
defer func(){
if r := recover(); r != nil {
if err, ok := r.(error); ok {
// We need only the first error, sync.Once is useful here.
g.errOnce.Do(func() {
g.err = err
})
} else {
panic(r)
}
}
}()
f()
}()
}
개선을 위한 피드백이나 제안을 부탁드립니다!
Reference
이 문제에 관하여(Don't Panic: Errgroup 고루틴에서 패닉 잡기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/stevenacoffman/don-t-panic-catching-panics-in-errgroup-5hn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)