Files
hermes-agent/apps/desktop/electron/ssh-teardown.ts
T
brooklyn! 8607d6a52a fix(desktop): retain and cancel owned backend lifecycle work
Track pending starts, pre-claim children, and teardown removed from routing. Bound cleanup and cancel setup/update waits while preserving settled remote descriptors.

Co-authored-by: Gille <4317663+helix4u@users.noreply.github.com>

Co-authored-by: ChanPark03 <parkchan0302@gmail.com>
2026-09-11 07:33:17 -05:00

39 lines
1.3 KiB
TypeScript

import { waitForTeardown } from './local-backend-lifecycle'
/** Retain transports removed from routing until their remote kill has settled. */
export function createSshTeardownTracker() {
const pending = new Map<Promise<void>, { close: () => Promise<unknown> }>()
return {
hasPending: () => pending.size > 0,
track(ssh: { close: () => Promise<unknown> }, teardown: () => Promise<void>): Promise<void> {
const promise = Promise.resolve().then(teardown)
pending.set(promise, ssh)
void promise.then(
() => pending.delete(promise),
() => pending.delete(promise)
)
return promise
},
async finish(
bootstraps: Promise<unknown>[],
forceCleanup: () => Promise<unknown>,
graceMs = 6_000,
forceMs = 1_000
) {
await waitForTeardown([...pending.keys(), ...bootstraps], graceMs)
// Only abandon the transport after the existing remote-kill grace period.
// Closing SSH unblocks a wedged exec; both close and bootstrap force cleanup
// are bounded too, not an unbounded await after a nominal timeout.
await waitForTeardown(
[
Promise.resolve().then(forceCleanup),
...[...new Set(pending.values())].map(ssh => Promise.resolve().then(() => ssh.close()))
],
forceMs
)
}
}
}