In this lesson, you will learn how to safely stop your Node.js WebSocket server by ensuring all active client connections are cleanly closed before the process exits.
Why Graceful Shutdowns Matter
When you stop a Node.js process abruptly (e.g., via Ctrl+C or a deployment signal), active WebSocket connections are severed instantly. To the client, this looks like a network failure rather than a scheduled maintenance event. This can lead to lost messages, corrupted state, or abrupt UI "reconnecting" loops. A graceful shutdown allows your server to notify clients, finish processing current tasks, and close sockets politely.
The Shutdown Workflow
To implement this, we listen for termination signals like SIGTERM or SIGINT. When these occur, we perform three distinct steps:
- Stop accepting new connections: Tell the server to stop listening for new handshake requests.
- Notify clients: Emit a "server-closing" event so clients can pause operations or show a "Going offline" notice.
- Close existing connections: Force-close active sockets to allow the event loop to empty.
Here is how you handle the process signals:
process.on('SIGTERM', async () => {
console.log('Shutting down gracefully...');
// 1. Stop the HTTP server from accepting new connections
server.close(async () => {
console.log('HTTP server closed.');
process.exit(0);
});
// 2. Notify all connected clients
io.emit('server-maintenance', { message: 'Server is restarting' });
// 3. Close all active socket connections
// Depending on your version, you can iterate through the adapter
for (const [id, socket] of io.of('/').sockets) {
socket.disconnect(true); // 'true' forces the close
}
});
Considerations for Real-Time Apps
If you are using a distributed setup (like a Redis adapter), ensure your shutdown sequence waits for any pending Pub/Sub events to clear before calling process.exit(0). By signaling the intent to close before terminating the process, you provide a seamless transition for your users, allowing their client-side logic to trigger a clean "offline" state rather than an unexpected error.
Key Takeaway: A graceful shutdown ensures that by notifying clients and closing existing sockets before terminating the process, you prevent data loss and provide a professional, error-free experience during deployments.