mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
fix(relay): close client when pty.replay overflows control queue
Replay is never retried, so it uses the control lane where overflow is fatal — the writer closes the client and reconnect reloads history rather than stranding a short buffer.
This commit is contained in:
@@ -764,6 +764,8 @@ function configureRelaySessionCallbacks(session: SshRelaySession): void {
|
||||
clearRelayLostBackoff(tid)
|
||||
return
|
||||
}
|
||||
// Why: still mid-transition — re-arm at the max delay without consuming an attempt. It ends once
|
||||
// the transport settles: 'connected' redeploys, a terminal status or a dropped session clears above.
|
||||
scheduleRelayRedeploy(RELAY_LOST_MAX_DELAY_MS)
|
||||
}, delay)
|
||||
relayLostBackoff.set(tid, state)
|
||||
|
||||
@@ -300,6 +300,26 @@ describe('RelayDispatcher bounded-capacity degradation', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('closes the client when pty.replay overflows the control queue', () => {
|
||||
const primary = makeSaturatingClient(65536)
|
||||
const stderr = vi.spyOn(process.stderr, 'write').mockReturnValue(true)
|
||||
const bounded = new RelayDispatcher(primary.write, primary.options)
|
||||
try {
|
||||
const clientId = bounded.activeClientIds()[0]
|
||||
for (let index = 0; index < DISPATCHER_CONTROL_QUEUE_MAX_FRAMES; index += 1) {
|
||||
bounded.notifyClient(clientId, `control.${index}`)
|
||||
}
|
||||
expect(primary.closes).toBe(0)
|
||||
|
||||
// Replay is never retried, so an unnoticed drop would strand the pane on a short buffer.
|
||||
bounded.notify('pty.replay', { paneKey: 'tab-1:pane-1', data: 'x' })
|
||||
expect(primary.closes).toBe(1)
|
||||
} finally {
|
||||
stderr.mockRestore()
|
||||
bounded.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('publishProducerNotification reports its drops like notify', () => {
|
||||
const primary = makeBoundedClient(65536)
|
||||
const secondary = makeBoundedClient(16384)
|
||||
|
||||
@@ -486,6 +486,8 @@ export class RelayDispatcher {
|
||||
continue
|
||||
}
|
||||
if (method === 'pty.replay') {
|
||||
// Why: replay is never re-sent, so it takes the control lane where overflow is fatal — the
|
||||
// writer closes the client and reconnect reloads history rather than stranding a short buffer.
|
||||
this.enqueueFrame(client, msg, 'control', undefined, frameBytes)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user