69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package misc
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"sync"
|
|
)
|
|
|
|
type (
|
|
handlerImpl struct {
|
|
errorChan chan error
|
|
ctx context.Context
|
|
canceler context.CancelFunc
|
|
waiter sync.WaitGroup
|
|
}
|
|
|
|
// Handler is context handler with sync.WaitGroup and error notifier.
|
|
Handler interface {
|
|
// NotifyError is an error notifier method within a concurrency environment that avoids falling in deadlock.
|
|
NotifyError(err error)
|
|
// Error method is a Error channel for cancellation.
|
|
Error() <-chan error
|
|
// Done method is a Done channel for cancellation.
|
|
Done() <-chan struct{}
|
|
// GracefulWait is a graceful shutdown method while the dependents are safely released.
|
|
// It acts like a "WaitGroup.Wait" method.
|
|
GracefulWait()
|
|
// IncreaseWait is an acquiring method for a dependent.
|
|
// It acts like a "WaitGroup.Add(1)" method.
|
|
IncreaseWait()
|
|
// DecreaseWait is an release method for a dependent.
|
|
// It acts like a "WaitGroup.Done" method.
|
|
DecreaseWait()
|
|
}
|
|
)
|
|
|
|
// NewHandler returns an initialized Handler interface.
|
|
func NewHandler(ctx context.Context) Handler {
|
|
ctx, canceler := context.WithCancel(ctx)
|
|
return &handlerImpl{
|
|
ctx: ctx,
|
|
canceler: canceler,
|
|
errorChan: make(chan error, 5),
|
|
}
|
|
}
|
|
|
|
func (h *handlerImpl) NotifyError(err error) { h.errorChan <- err }
|
|
func (h *handlerImpl) Error() <-chan error { return h.errorChan }
|
|
func (h *handlerImpl) Done() <-chan struct{} { return h.ctx.Done() }
|
|
func (h *handlerImpl) GracefulWait() {
|
|
if h.ctx.Err() == nil {
|
|
h.canceler()
|
|
}
|
|
|
|
h.waiter.Wait()
|
|
close(h.errorChan)
|
|
|
|
for remainError := range h.errorChan {
|
|
log.Println("remain errors ", remainError)
|
|
}
|
|
}
|
|
|
|
func (h *handlerImpl) IncreaseWait() {
|
|
h.waiter.Add(1)
|
|
}
|
|
func (h *handlerImpl) DecreaseWait() {
|
|
h.waiter.Done()
|
|
}
|