fix: abort relay requests on dispatcher dispose

This commit is contained in:
Neil 2026-05-29 02:00:53 -07:00 committed by GitHub
parent 539f704bdb
commit 1236729b24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 0 deletions

View File

@ -27,6 +27,13 @@ export class ClientRequestAborts {
}
}
abortAll(): void {
for (const [, controller] of this.controllers) {
controller.abort()
}
this.controllers.clear()
}
private key(clientId: number, requestId: number): string {
return `${clientId}:${requestId}`
}

View File

@ -310,6 +310,28 @@ describe('RelayDispatcher', () => {
await vi.advanceTimersByTimeAsync(0)
})
it('aborts in-flight request contexts on dispose', async () => {
let observedSignal: AbortSignal | undefined
let resolveHandler!: () => void
dispatcher.onRequest(
'slow.method',
(_params, context) =>
new Promise((resolve) => {
observedSignal = context.signal
resolveHandler = () => resolve(null)
})
)
const req: JsonRpcRequest = { jsonrpc: '2.0', id: 101, method: 'slow.method' }
dispatcher.feed(encodeJsonRpcFrame(req, 1, 0))
await vi.advanceTimersByTimeAsync(0)
dispatcher.dispose()
expect(observedSignal?.aborted).toBe(true)
resolveHandler()
await vi.advanceTimersByTimeAsync(0)
})
it('notifies listeners when the primary client is invalidated', () => {
const listener = vi.fn()
dispatcher.onClientDetached(listener)

View File

@ -162,6 +162,9 @@ export class RelayDispatcher {
clearInterval(this.keepaliveTimer)
this.keepaliveTimer = null
}
// Why: dispose means this relay instance cannot send responses anymore;
// abort in-flight request work so stale SSH-side scans/watchers release.
this.requestAborts.abortAll()
}
private createClient(write: (data: Buffer) => void): RelayClient {