50 lines
1.1 KiB
Go
50 lines
1.1 KiB
Go
|
package stop
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// Chan is a receive-only channel
|
||
|
type Chan <-chan struct{}
|
||
|
|
||
|
// Stopper extends sync.WaitGroup to add a convenient way to stop running goroutines
|
||
|
type Group struct {
|
||
|
sync.WaitGroup
|
||
|
ctx context.Context
|
||
|
cancel context.CancelFunc
|
||
|
}
|
||
|
type Stopper = Group
|
||
|
|
||
|
// New allocates and returns a new instance. Use New(parent) to create an instance that is stopped when parent is stopped.
|
||
|
func New(parent ...*Group) *Group {
|
||
|
s := &Group{}
|
||
|
ctx := context.Background()
|
||
|
if len(parent) > 0 && parent[0] != nil {
|
||
|
ctx = parent[0].ctx
|
||
|
}
|
||
|
s.ctx, s.cancel = context.WithCancel(ctx)
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Ch returns a channel that will be closed when Stop is called.
|
||
|
func (s *Group) Ch() Chan {
|
||
|
return s.ctx.Done()
|
||
|
}
|
||
|
|
||
|
// Stop signals any listening processes to stop. After the first call, Stop() does nothing.
|
||
|
func (s *Group) Stop() {
|
||
|
s.cancel()
|
||
|
}
|
||
|
|
||
|
// StopAndWait is a convenience method to close the channel and wait for goroutines to return.
|
||
|
func (s *Group) StopAndWait() {
|
||
|
s.Stop()
|
||
|
s.Wait()
|
||
|
}
|
||
|
|
||
|
// Child returns a new instance that will be stopped when s is stopped.
|
||
|
func (s *Group) Child() *Group {
|
||
|
return New(s)
|
||
|
}
|