2026-06-23 11:53:00 +08:00

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()
}