refactor(subprocess): derive termination state

This commit is contained in:
pku-xht
2026-08-04 20:55:29 +08:00
parent 8067701b92
commit 74f2ab90e1

View File

@@ -383,7 +383,6 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
const stderrCollector = collectStream(errMode, child.stderr, 'stderr') const stderrCollector = collectStream(errMode, child.stderr, 'stderr')
let graceTimer: ReturnType<typeof scheduleFiniteTimeout> | undefined let graceTimer: ReturnType<typeof scheduleFiniteTimeout> | undefined
let terminationStarted = false
let treeExitObserved = false let treeExitObserved = false
let treeExitObservation: Promise<void> | undefined let treeExitObservation: Promise<void> | undefined
let settled = false let settled = false
@@ -427,7 +426,6 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
treeExitObservation ??= (async () => { treeExitObservation ??= (async () => {
while (treeAlive()) await sleepTick() while (treeAlive()) await sleepTick()
treeExitObserved = true treeExitObserved = true
terminationStarted = true
graceTimer?.cancel() graceTimer?.cancel()
graceTimer = undefined graceTimer = undefined
})() })()
@@ -447,11 +445,11 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
} }
const terminate = (): void => { const terminate = (): void => {
if (terminationStarted) return if (treeExitObserved || graceTimer !== undefined) return
terminationStarted = true
// Observe from the first termination tier onward, even when inherited // Observe from the first termination tier onward, even when inherited
// pipes delay `done` and no consumer has begun its own teardown wait. // pipes delay `done` and no consumer has begun its own teardown wait.
void observeTreeExit() void observeTreeExit()
// oxlint-disable-next-line typescript/no-unnecessary-condition -- observer can record absence before its first await.
if (treeExitObserved) return if (treeExitObserved) return
kill('SIGTERM') kill('SIGTERM')
// The escalation must survive direct-child settlement — the leader dying // The escalation must survive direct-child settlement — the leader dying