fix(desktop): tear down SSH lifecycle when a pooled backend is stopped

Idle-reaper and LRU eviction only called stopPoolBackend, which left sshConnections and the keep-alive WS armed on process-less remote descriptors.
This commit is contained in:
KoNit-K
2026-09-10 10:45:03 +08:00
committed by kshitij
parent e785128934
commit be69a8d043
2 changed files with 28 additions and 0 deletions
+5
View File
@@ -12744,6 +12744,11 @@ async function stopPoolBackend(profile: string) {
const entry = backendPool.get(profile)
await poolStopper.stop(profile)
releaseLocalBackendSlot(entry)
// Remote / SSH-isolated pool entries keep `process: null`. Evicting the
// descriptor alone leaves sshConnections + the keep-alive WS armed, so
// idle-reaper / LRU retirement would pin the tunnel indefinitely (#106935).
await sshBootstrapCoordinator.cancelAndWait(profile)
await teardownSshConnection(profile)
}
async function teardownPoolBackendAndWait(profile) {
@@ -70,6 +70,29 @@ describe('main.ts wiring for SSH-isolated keep-alive WS (#106935)', () => {
expect(body).toMatch(/sshIsolatedKeepalives\.stop\(\s*scope/)
})
it('stopPoolBackend tears down the matching SSH lifecycle (idle-reaper / LRU)', () => {
const fnStart = mainSource.indexOf('async function stopPoolBackend(')
expect(fnStart).toBeGreaterThan(-1)
const nextFn = mainSource.indexOf('\nasync function teardownPoolBackendAndWait(', fnStart + 1)
const body = mainSource.slice(fnStart, nextFn === -1 ? fnStart + 400 : nextFn)
expect(body).toMatch(/sshBootstrapCoordinator\.cancelAndWait\(\s*profile/)
expect(body).toMatch(/teardownSshConnection\(\s*profile/)
})
it('idle reaper retires descriptors only through stopPoolBackend', () => {
const fnStart = mainSource.indexOf('function startPoolIdleReaper(')
expect(fnStart).toBeGreaterThan(-1)
const nextFn = mainSource.indexOf('\nfunction releaseLocalBackendSlot(', fnStart + 1)
const body = mainSource.slice(fnStart, nextFn === -1 ? fnStart + 800 : nextFn)
expect(body).toContain('stopPoolBackend(profile)')
expect(body).not.toMatch(/backendPool\.delete/)
expect(body).not.toMatch(/sshConnections\.delete/)
})
it('imports the keep-alive registry from the electron helper (not inline in main)', () => {
expect(mainSource).toMatch(/createSshIsolatedKeepaliveRegistry/)
expect(mainSource).toMatch(/from '\.\/ssh-isolated-keepalive'/)