github.com/weaviate/weaviate@v1.24.6/entities/errors/error_group_wrapper.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package errors 13 14 import ( 15 "context" 16 "fmt" 17 "os" 18 "runtime/debug" 19 20 "github.com/sirupsen/logrus" 21 "github.com/weaviate/weaviate/usecases/configbase" 22 23 "golang.org/x/sync/errgroup" 24 ) 25 26 // ErrorGroupWrapper is a custom type that embeds errgroup.Group. 27 type ErrorGroupWrapper struct { 28 *errgroup.Group 29 returnError error 30 variables []interface{} 31 logger logrus.FieldLogger 32 deferFunc func(localVars ...interface{}) 33 } 34 35 // NewErrorGroupWrapper creates a new ErrorGroupWrapper. 36 func NewErrorGroupWrapper(logger logrus.FieldLogger, vars ...interface{}) *ErrorGroupWrapper { 37 egw := &ErrorGroupWrapper{ 38 Group: new(errgroup.Group), 39 returnError: nil, 40 variables: vars, 41 logger: logger, 42 } 43 egw.setDeferFunc() 44 return egw 45 } 46 47 // NewErrorGroupWithContextWrapper creates a new ErrorGroupWrapper 48 func NewErrorGroupWithContextWrapper(logger logrus.FieldLogger, ctx context.Context, vars ...interface{}) (*ErrorGroupWrapper, context.Context) { 49 eg, ctx := errgroup.WithContext(ctx) 50 egw := &ErrorGroupWrapper{ 51 Group: eg, 52 returnError: nil, 53 variables: vars, 54 logger: logger, 55 } 56 egw.setDeferFunc() 57 58 return egw, ctx 59 } 60 61 func (egw *ErrorGroupWrapper) setDeferFunc() { 62 disable := configbase.Enabled(os.Getenv("DISABLE_RECOVERY_ON_PANIC")) 63 if !disable { 64 egw.deferFunc = func(localVars ...interface{}) { 65 if r := recover(); r != nil { 66 egw.logger.WithField("panic", r).Errorf("Recovered from panic: %v, local variables %v, additional localVars %v\n", r, localVars, egw.variables) 67 debug.PrintStack() 68 egw.returnError = fmt.Errorf("panic occurred: %v", r) 69 } 70 } 71 } else { 72 egw.deferFunc = func(localVars ...interface{}) {} 73 } 74 } 75 76 // Go overrides the Go method to add panic recovery logic. 77 func (egw *ErrorGroupWrapper) Go(f func() error, localVars ...interface{}) { 78 egw.Group.Go(func() error { 79 defer egw.deferFunc(localVars) 80 return f() 81 }) 82 } 83 84 // Wait waits for all goroutines to finish and returns the first non-nil error. 85 func (egw *ErrorGroupWrapper) Wait() error { 86 if err := egw.Group.Wait(); err != nil { 87 return err 88 } 89 return egw.returnError 90 }