* HH-442: isolate runtime processes and harden shutdown * HH-442: harden worker shutdown races * HH-442: gate dependency shutdown on active handlers --------- Co-authored-by: Rogee <rogee@ipao.vip>
64 lines
1.0 KiB
Go
64 lines
1.0 KiB
Go
package lifecycle
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
// HandlerGroup stops new handlers, cancels their shared lifecycle context,
|
|
// and waits for handlers already using application dependencies.
|
|
type HandlerGroup struct {
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
|
|
mu sync.Mutex
|
|
done *sync.Cond
|
|
active int
|
|
stopped bool
|
|
}
|
|
|
|
func NewHandlerGroup() *HandlerGroup {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
g := &HandlerGroup{ctx: ctx, cancel: cancel}
|
|
g.done = sync.NewCond(&g.mu)
|
|
return g
|
|
}
|
|
|
|
func (g *HandlerGroup) Context() context.Context { return g.ctx }
|
|
|
|
func (g *HandlerGroup) Begin() bool {
|
|
g.mu.Lock()
|
|
defer g.mu.Unlock()
|
|
if g.stopped {
|
|
return false
|
|
}
|
|
g.active++
|
|
return true
|
|
}
|
|
|
|
func (g *HandlerGroup) Done() {
|
|
g.mu.Lock()
|
|
g.active--
|
|
if g.active == 0 {
|
|
g.done.Broadcast()
|
|
}
|
|
g.mu.Unlock()
|
|
}
|
|
|
|
func (g *HandlerGroup) Stop() {
|
|
g.mu.Lock()
|
|
if !g.stopped {
|
|
g.stopped = true
|
|
g.cancel()
|
|
}
|
|
g.mu.Unlock()
|
|
}
|
|
|
|
func (g *HandlerGroup) Wait() {
|
|
g.mu.Lock()
|
|
for g.active != 0 {
|
|
g.done.Wait()
|
|
}
|
|
g.mu.Unlock()
|
|
}
|