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  }