You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
1.4 KiB
65 lines
1.4 KiB
3 years ago
|
package tdsync
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// Supervisor is simple task group primitive to control multiple
|
||
|
// long-live tasks.
|
||
|
// Unlike Groups, Supervisor does not cancel when one task is failed.
|
||
|
// Unlike WaitGroup and errgroup.Group this is not allowed to use zero value.
|
||
|
type Supervisor struct {
|
||
|
wg sync.WaitGroup
|
||
|
|
||
|
ctx context.Context
|
||
|
cancel context.CancelFunc
|
||
|
|
||
|
onError func(err error)
|
||
|
}
|
||
|
|
||
|
// NewSupervisor creates new Supervisor.
|
||
|
func NewSupervisor(parent context.Context) *Supervisor {
|
||
|
ctx, cancel := context.WithCancel(parent)
|
||
|
|
||
|
return &Supervisor{
|
||
|
ctx: ctx,
|
||
|
cancel: cancel,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WithErrorHandler sets tasks error handler
|
||
|
// Must be called before any Go calls.
|
||
|
func (s *Supervisor) WithErrorHandler(h func(err error)) *Supervisor {
|
||
|
s.onError = h
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Go calls the given function in a new goroutine.
|
||
|
func (s *Supervisor) Go(task func(ctx context.Context) error) {
|
||
|
s.wg.Add(1)
|
||
|
go func() {
|
||
|
defer s.wg.Done()
|
||
|
|
||
|
if err := task(s.ctx); err != nil {
|
||
|
if s.onError != nil {
|
||
|
s.onError(err)
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
|
||
|
// Cancel cancels all goroutines in group.
|
||
|
//
|
||
|
// Note: context cancellation error can be returned by Wait().
|
||
|
func (s *Supervisor) Cancel() {
|
||
|
s.cancel()
|
||
|
}
|
||
|
|
||
|
// Wait blocks until all function calls from the Go method have returned, then
|
||
|
// returns the first non-nil error (if any) from them.
|
||
|
func (s *Supervisor) Wait() error {
|
||
|
s.wg.Wait()
|
||
|
return nil
|
||
|
}
|