include better error handling for the /sse route

This commit is contained in:
Lee Hanken
2025-10-26 13:06:03 +00:00
parent 41464a1244
commit eef88341f7

View File

@@ -700,18 +700,18 @@ app.get('/health', (req, res) => {
// SSE endpoint for MCP // SSE endpoint for MCP
app.get('/sse', async (req, res) => { app.get('/sse', async (req, res) => {
let pingInterval = null; // Declare pingInterval to be accessible in req.on('close') let pingInterval = null;
// NEW FLAG: Tracks if the 200 SSE headers have been flushed
let headersSent = false;
try { try {
// Check system health // Check system health (MUST be done before sending headers)
checkMemory(); checkMemory();
checkConcurrency(); checkConcurrency();
activeRequests++; activeRequests++;
console.error(`New SSE connection. Active requests: ${activeRequests}`); console.error(`New SSE connection. Active requests: ${activeRequests}`);
// === START SSE FIXES FOR RENDER/PROXY TIMEOUTS ===
// 1. Send no-buffering headers and flush immediately // 1. Send no-buffering headers and flush immediately
res.writeHead(200, { res.writeHead(200, {
'Content-Type': 'text/event-stream', 'Content-Type': 'text/event-stream',
@@ -723,18 +723,15 @@ app.get('/sse', async (req, res) => {
// Send an initial comment (ping) to complete the HTTP handshake and flush headers // Send an initial comment (ping) to complete the HTTP handshake and flush headers
res.write(':\n'); res.write(':\n');
res.flushHeaders(); res.flushHeaders();
headersSent = true; // Flag is set after successful header flush
// 2. Start the heartbeat/ping interval // 2. Start the heartbeat/ping interval
pingInterval = setInterval(() => { pingInterval = setInterval(() => {
// Send a comment line (which is ignored by clients) every 20s // Send a comment line (ignored by clients) every 20s to keep the proxy alive
res.write(':\n'); res.write(':\n');
// NOTE: In a real-world scenario, you might also need to call res.flush()
// or ensure your underlying HTTP library flushes the write.
}, SSE_HEARTBEAT_INTERVAL_MS); }, SSE_HEARTBEAT_INTERVAL_MS);
// === END SSE FIXES ===
// Create a new MCP server instance for this connection // Create a new MCP server instance for this connection
const server = createMCPServer(); const server = createMCPServer();
@@ -763,15 +760,25 @@ app.get('/sse', async (req, res) => {
} }
console.error('SSE connection error:', error.message); console.error('SSE connection error:', error.message);
if (!res.headersSent) { // --- START CORRECTED ERROR HANDLING ---
// Send a 503 error if headers haven't been sent yet if (!headersSent) {
// Case 1: Error before SSE headers were flushed (e.g., checkMemory failed)
// Send a standard HTTP error response.
res.status(503).json({ res.status(503).json({
error: error.message, error: error.message,
circuitBreaker: circuitBreaker.state, circuitBreaker: circuitBreaker.state,
}); });
} else {
// Case 2: Error after SSE headers were flushed (stream is open)
// Cannot change status. Send an SSE 'error' event and end the connection.
const errorData = JSON.stringify({
message: error.message,
circuitBreaker: circuitBreaker.state
});
res.write(`event: error\ndata: ${errorData}\n\n`);
res.end(); // Forcefully close the connection
} }
// If headers were sent (i.e., stream started but failed mid-way), // --- END CORRECTED ERROR HANDLING ---
// simply let the connection close, which the client will see as an error.
} }
}); });