Files
ThothII/tools/tht/internal/compose/process_termination.go
T

57 lines
1.6 KiB
Go

package compose
import (
"errors"
"os"
"time"
)
// processLifetime owns a started Docker CLI process until it has been reaped and every process
// it may have started has been released. Platform implementations must make close idempotent.
type processLifetime interface {
terminate(done <-chan error) error
close() error
}
var startProcessForRunner = startProcess
var terminateProcessForRunner = func(process processLifetime, done <-chan error) error {
return process.terminate(done)
}
// terminateProcessTree terminates the owned tree before consulting the direct child's reaping
// result. A direct child can be reaped while descendants survive, so a ready done channel is never
// evidence that tree termination can be skipped. The direct kill is only a fallback when tree
// ownership could not terminate the tree; an already-reaped direct child is benign in that case.
func terminateProcessTree(
done <-chan error,
terminateTree func() error,
terminateDirect func() error,
bound time.Duration,
) error {
treeErr := terminateTree()
var directErr error
if treeErr != nil {
directErr = terminateDirect()
if errors.Is(directErr, os.ErrProcessDone) {
directErr = nil
}
}
reapErr := waitForProcessReap(done, bound)
if treeErr == nil && directErr == nil && reapErr == nil {
return nil
}
return errors.Join(ErrProcessReap, treeErr, directErr, reapErr)
}
func waitForProcessReap(done <-chan error, bound time.Duration) error {
timer := time.NewTimer(bound)
defer timer.Stop()
select {
case <-done:
return nil
case <-timer.C:
return ErrProcessReap
}
}