Build an SSE stream
Heartbeat and clean up
Keep intermediaries aware of quiet streams and release resources as soon as a client leaves.
A quiet incident board still holds a long HTTP response open. Proxies, load balancers, and browsers all impose idle timeouts. If nothing crosses the wire for two minutes, something in the path may cut the stream even though your process is fine.
Send a modest heartbeat on idle streams, and tear down timers the moment the client leaves.
Comment heartbeat
SSE comments start with : and are ignored by the client:
const heartbeat = setInterval(() => {
res.write(': ping\n\n')
}, 25000)
Open the stream with curl and wait. Every twenty-five seconds you should see : ping even when no incidents changed. That keeps intermediaries from treating the connection as stuck.
Clean up on close
Each subscriber costs memory and a timer. Wire cleanup to the request abort:
let active = 0
function subscribe(req, res) {
active += 1
console.log('active connections', active)
const heartbeat = setInterval(() => {
res.write(': ping\n\n')
}, 25000)
req.on('close', () => {
clearInterval(heartbeat)
active -= 1
console.log('active connections', active)
})
}
Open twenty tabs, then close them. The logged count must return to zero. If it does not, you leaked a timer or a Map entry.
AbortSignal on the client
When the user navigates away, close the source:
const source = new EventSource('/events')
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
source.close()
}
})
For a dashboard that should stay live in background tabs, skip the close on hide. For a tutorial service, prove cleanup explicitly.
Run the open-and-close test before you load test. Leaked intervals show up as climbing memory long before you hit ten thousand viewers.
Proxy idle timeouts
Some corporate proxies kill quiet streams at sixty seconds even when your server heartbeats at twenty-five. If users report random disconnects, compare their network to your lab. You may need a shorter heartbeat, not a new protocol.
Try this on your own project: track active connections and timer count, open twenty clients, close them all, and confirm both metrics return to baseline.
Lesson completed