62 lines
1.4 KiB
Go
62 lines
1.4 KiB
Go
// Package app provides small process lifecycle primitives for service app packages.
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
// BackgroundGroup owns a cancellable worker context and waits for all registered workers to finish.
|
|
type BackgroundGroup struct {
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
wg sync.WaitGroup
|
|
once sync.Once
|
|
}
|
|
|
|
// NewBackground creates a worker group rooted at parent; nil parent means context.Background.
|
|
func NewBackground(parent context.Context) *BackgroundGroup {
|
|
if parent == nil {
|
|
parent = context.Background()
|
|
}
|
|
ctx, cancel := context.WithCancel(parent)
|
|
return &BackgroundGroup{ctx: ctx, cancel: cancel}
|
|
}
|
|
|
|
// Context returns the shared worker context. Workers should stop when it is canceled.
|
|
func (g *BackgroundGroup) Context() context.Context {
|
|
if g == nil || g.ctx == nil {
|
|
return context.Background()
|
|
}
|
|
return g.ctx
|
|
}
|
|
|
|
// Go starts one worker and gives it the shared cancellable context.
|
|
func (g *BackgroundGroup) Go(run func(context.Context)) {
|
|
if g == nil || run == nil {
|
|
return
|
|
}
|
|
g.wg.Add(1)
|
|
go func() {
|
|
defer g.wg.Done()
|
|
run(g.Context())
|
|
}()
|
|
}
|
|
|
|
// Stop cancels the shared worker context. It is safe to call more than once.
|
|
func (g *BackgroundGroup) Stop() {
|
|
if g == nil {
|
|
return
|
|
}
|
|
g.once.Do(g.cancel)
|
|
}
|
|
|
|
// StopAndWait cancels the shared context and waits for all workers to return.
|
|
func (g *BackgroundGroup) StopAndWait() {
|
|
if g == nil {
|
|
return
|
|
}
|
|
g.Stop()
|
|
g.wg.Wait()
|
|
}
|