fix(lifecycle): retain parent cancellation at every shutdown return
Documentation / docs (pull_request) Successful in 16s
ci / check (pull_request) Successful in 1m33s

This commit is contained in:
end committed 2026-10-27 12:11:59 -07:00
1 parent 64c7e6b65d
commit f4abb626c6
2 files changed
+90 -30

No files matched your search

+8 -9
View File
@@ -238,7 +238,7 @@ func (a *App) Run(parent context.Context) error {
if !ok {
signals = nil
} else if err := receiveSignal(sig); err != nil {
return a.result(err)
return a.result(parent, err)
}
continue
default:
@@ -246,7 +246,6 @@ func (a *App) Run(parent context.Context) error {
a.mu.Lock()
if !a.stopping && parent.Err() != nil {
a.errs = append(a.errs, parent.Err())
a.stopLocked()
parentDone = nil
}
@@ -288,7 +287,7 @@ func (a *App) Run(parent context.Context) error {
if stopping {
if err := shutdown.Err(); err != nil {
return a.result(err)
return a.result(parent, err)
}
if setupDone == nil && teardownDone == nil {
if teardownIndex >= 0 {
@@ -297,7 +296,7 @@ func (a *App) Run(parent context.Context) error {
teardownDone = result
go func() { result <- m.Teardown(shutdown) }()
} else if active == 0 {
return a.result(nil)
return a.result(parent, nil)
}
}
}
@@ -325,7 +324,6 @@ func (a *App) Run(parent context.Context) error {
case <-a.wake:
case <-parentDone:
a.mu.Lock()
a.errs = append(a.errs, parent.Err())
a.stopLocked()
a.mu.Unlock()
parentDone = nil
@@ -335,16 +333,17 @@ func (a *App) Run(parent context.Context) error {
continue
}
if err := receiveSignal(sig); err != nil {
return a.result(err)
return a.result(parent, err)
}
case <-deadline:
return a.result(context.DeadlineExceeded)
return a.result(parent, context.DeadlineExceeded)
}
}
}
func (a *App) result(extra error) error {
func (a *App) result(parent context.Context, extra error) error {
a.mu.Lock()
defer a.mu.Unlock()
return errors.Join(append(a.errs, extra)...)
// invariant: every completion and abandonment retains parent cancellation exactly once.
return errors.Join(append(a.errs, parent.Err(), extra)...)
}