github.com/spi-ca/misc@v1.0.1/context.go (about) 1 package misc 2 3 import ( 4 "context" 5 "log" 6 "sync" 7 ) 8 9 type ( 10 handlerImpl struct { 11 errorChan chan error 12 ctx context.Context 13 canceler context.CancelFunc 14 waiter sync.WaitGroup 15 } 16 17 // Handler is context handler with sync.WaitGroup and error notifier. 18 Handler interface { 19 // NotifyError is an error notifier method within a concurrency environment that avoids falling in deadlock. 20 NotifyError(err error) 21 // Error method is a Error channel for cancellation. 22 Error() <-chan error 23 // Done method is a Done channel for cancellation. 24 Done() <-chan struct{} 25 // GracefulWait is a graceful shutdown method while the dependents are safely released. 26 // It acts like a "WaitGroup.Wait" method. 27 GracefulWait() 28 // IncreaseWait is an acquiring method for a dependent. 29 // It acts like a "WaitGroup.Add(1)" method. 30 IncreaseWait() 31 // DecreaseWait is an release method for a dependent. 32 // It acts like a "WaitGroup.Done" method. 33 DecreaseWait() 34 } 35 ) 36 37 // NewHandler returns an initialized Handler interface. 38 func NewHandler(ctx context.Context) Handler { 39 ctx, canceler := context.WithCancel(ctx) 40 return &handlerImpl{ 41 ctx: ctx, 42 canceler: canceler, 43 errorChan: make(chan error, 5), 44 } 45 } 46 47 func (h *handlerImpl) NotifyError(err error) { h.errorChan <- err } 48 func (h *handlerImpl) Error() <-chan error { return h.errorChan } 49 func (h *handlerImpl) Done() <-chan struct{} { return h.ctx.Done() } 50 func (h *handlerImpl) GracefulWait() { 51 if h.ctx.Err() == nil { 52 h.canceler() 53 } 54 55 h.waiter.Wait() 56 close(h.errorChan) 57 58 for remainError := range h.errorChan { 59 log.Println("remain errors ", remainError) 60 } 61 } 62 63 func (h *handlerImpl) IncreaseWait() { 64 h.waiter.Add(1) 65 } 66 func (h *handlerImpl) DecreaseWait() { 67 h.waiter.Done() 68 }