fix(daemon): stop login watch before clean shutdown

This commit is contained in:
Brennan Benson
2026-07-22 12:42:40 -07:00
parent ebdd072e50
commit c41fb06363
2 changed files with 26 additions and 1 deletions
+4 -1
View File
@@ -135,6 +135,7 @@ async function main(): Promise<void> {
})
let daemon: DaemonHandle | null = null
let deathWatch: MacosLoginSessionDeathWatch | null = null
let shuttingDown = false
// Bound the wait so a wedged native shutdown can't leave the daemon running
// forever on SIGTERM/SIGINT (it would then survive a real quit, not just updates).
@@ -146,6 +147,7 @@ async function main(): Promise<void> {
return
}
shuttingDown = true
deathWatch?.stop()
daemonLog.log('shutdown', { reason })
try {
if (daemon) {
@@ -181,7 +183,7 @@ async function main(): Promise<void> {
return ''
}
}
const deathWatch =
deathWatch =
loginSessionWatch && process.platform === 'darwin'
? new MacosLoginSessionDeathWatch({
probeLoginSession: e2eProbeFile
@@ -242,6 +244,7 @@ async function main(): Promise<void> {
: {}),
spawnSubprocess: (opts) => createPtySubprocess(opts),
onIdleShutdown: () => {
deathWatch?.stop()
shuttingDown = true
daemonLog.log('shutdown', { reason: 'idle' })
daemonLog.close()
@@ -255,6 +255,28 @@ describe('MacosLoginSessionDeathWatch', () => {
expect(clock.pendingCount()).toBe(0)
})
it('stop() prevents an in-flight resolver check from retiring the daemon', async () => {
let resolveHealth!: (health: SystemResolverHealth) => void
const resolverHealth = new Promise<SystemResolverHealth>((resolve) => {
resolveHealth = resolve
})
const { watch, clock, onRetire } = createWatch({
outcomes: [ACCEPTED, REJECTED, REJECTED, REJECTED],
readResolverHealth: () => resolverHealth
})
watch.start()
await drainMicrotasks()
await clock.advance(120_000)
await clock.advance(10_000)
await clock.advance(10_000) // retirement is now waiting on resolver health
watch.stop()
resolveHealth('unhealthy')
await drainMicrotasks()
expect(onRetire).not.toHaveBeenCalled()
})
it('logs and reschedules when a probe throws instead of surfacing a rejection', async () => {
const outcomes: (() => Promise<LoginPreflightOutcome>)[] = [
async () => ACCEPTED,