From df12c3a2b5d8348ba16e4d00aaafe66fff123d98 Mon Sep 17 00:00:00 2001 From: Isaac Sanchez-Hawkins <266845420+isanchez404@users.noreply.github.com> Date: Tue, 12 May 2026 04:01:47 -0400 Subject: [PATCH] fix(terminal): make SSE cleanup idempotent (#1234) Co-authored-by: Isaac Sanchez --- packages/web/server/lib/terminal/runtime.js | 57 +++++++++++++-------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/web/server/lib/terminal/runtime.js b/packages/web/server/lib/terminal/runtime.js index 2d0ac299..03de97f9 100644 --- a/packages/web/server/lib/terminal/runtime.js +++ b/packages/web/server/lib/terminal/runtime.js @@ -572,6 +572,34 @@ export function createTerminalRuntime({ } }, 15000); + let cleanedUp = false; + let dataDisposable = null; + let exitDisposable = null; + const cleanup = () => { + if (cleanedUp) { + return; + } + + cleanedUp = true; + clearInterval(heartbeatInterval); + session.clients.delete(clientId); + + if (dataDisposable && typeof dataDisposable.dispose === 'function') { + dataDisposable.dispose(); + } + if (exitDisposable && typeof exitDisposable.dispose === 'function') { + exitDisposable.dispose(); + } + + try { + res.end(); + } catch (error) { + + } + + console.log(`Client ${clientId} disconnected from terminal session ${sessionId}`); + }; + const dataHandler = (data) => { try { session.lastActivity = Date.now(); @@ -600,28 +628,15 @@ export function createTerminalRuntime({ cleanup(); }; - const dataDisposable = session.ptyProcess.onData(dataHandler); - const exitDisposable = session.ptyProcess.onExit(exitHandler); + dataDisposable = session.ptyProcess.onData(dataHandler); + if (cleanedUp && dataDisposable && typeof dataDisposable.dispose === 'function') { + dataDisposable.dispose(); + } - const cleanup = () => { - clearInterval(heartbeatInterval); - session.clients.delete(clientId); - - if (dataDisposable && typeof dataDisposable.dispose === 'function') { - dataDisposable.dispose(); - } - if (exitDisposable && typeof exitDisposable.dispose === 'function') { - exitDisposable.dispose(); - } - - try { - res.end(); - } catch (error) { - - } - - console.log(`Client ${clientId} disconnected from terminal session ${sessionId}`); - }; + exitDisposable = session.ptyProcess.onExit(exitHandler); + if (cleanedUp && exitDisposable && typeof exitDisposable.dispose === 'function') { + exitDisposable.dispose(); + } req.on('close', cleanup); req.on('error', cleanup);