perf: Optimize SSE communication between browser and container
All checks were successful
build-and-deploy / deploy (push) Successful in 9s
build-and-deploy / build (push) Successful in 8s
build-and-deploy / filter (push) Successful in 2s

- Add anti-buffering headers (X-Accel-Buffering, Content-Encoding)
- Reduce polling interval from 500ms to 250ms for faster updates
- Add heartbeat mechanism to keep connection alive
- Implement auto-reconnection on client side
- Disable Express response buffering for SSE endpoints
- Skip empty heartbeat messages on client
- Improve error handling and logging
This commit is contained in:
2025-07-05 17:02:19 -06:00
parent 7de915166f
commit 1b3d43cfea
2 changed files with 39 additions and 4 deletions

View File

@@ -9,9 +9,22 @@ dotenv.config({ path: `.env.${ENV}` });
const app = express();
const PORT = process.env.PORT || 3002;
// Disable Express poweredBy header for performance
app.disable('x-powered-by');
// Parse JSON bodies
app.use(express.json());
// Optimize Express for SSE performance
app.use((req, res, next) => {
// Disable buffering for SSE endpoints
if (req.path === '/api/sse') {
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
}
next();
});
// Track SSE connections
let sseConnections = 0;
@@ -41,16 +54,24 @@ app.get('/api/sse', (req, res) => {
const connectionId = sseConnections;
console.log(`[SSE] New connection #${connectionId} established. Total: ${sseConnections}`);
// Optimized headers for better performance
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
'Access-Control-Allow-Headers': 'Cache-Control',
'X-Accel-Buffering': 'no', // Disable nginx buffering
'Content-Encoding': 'identity' // Disable compression
});
// Send initial connection message
res.write('data: {"type": "connected", "message": "SSE connection established"}\n\n');
// Send keepalive heartbeat every 30 seconds
const heartbeatInterval = setInterval(() => {
res.write(': heartbeat\n\n');
}, 30000);
// Set up polling interval for game state updates
const pollInterval = setInterval(async () => {
@@ -90,13 +111,14 @@ app.get('/api/sse', (req, res) => {
message: `Error fetching game stats: ${error.message}`
})}\n\n`);
}
}, 500); // Poll every 500ms
}, 250); // Poll every 250ms for faster updates
// Clean up on client disconnect
req.on('close', () => {
sseConnections--;
console.log(`[SSE] Connection #${connectionId} closed. Total: ${sseConnections}`);
clearInterval(pollInterval);
clearInterval(heartbeatInterval);
});
});