Websocket Reconnection
title: "WebSocket Reconnection" description: "Learn WebSocket reconnection strategies including exponential backoff, jitter, connection state management, and graceful recovery from network interruptions." weight: 22 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "websocket"]
Network interruptions are inevitable. WebSocket reconnection strategies ensure your application recovers gracefully from disconnections without data loss or user-facing errors.
## What You'll Learn
- Why WebSocket reconnection is necessary
- Exponential backoff algorithms
- Adding jitter to prevent thundering herds
- Connection state management
- Reconnection with message replay
## Why It Matters
Without reconnection, a brief network interruption forces users to reload the page and lose context. Proper reconnection provides a seamless user experience even during network instability.
## Real-World Use
A mobile trading app uses exponential backoff with jitter for WebSocket reconnection. When a user enters a subway tunnel, the connection drops and reconnects automatically within seconds, without losing any trade confirmations.
## Flow Chart
```mermaid
stateDiagram-v2
[*] --> Connected
Connected --> Disconnected: Network Error
Disconnected --> Reconnecting: Start Reconnect
Reconnecting --> Connected: Success
Reconnecting --> Backoff: Failed
Backoff --> Reconnecting: Wait Complete
Backoff --> MaxRetries: Exceeded Limit
MaxRetries --> [*]: Give Up
Code Examples
Example 1: Reconnection with Exponential Backoff
class ReconnectingWebSocket {
constructor(url, options = {}) {
this.url = url;
this.maxRetries = options.maxRetries || Infinity;
this.maxDelay = options.maxDelay || 30000;
this.baseDelay = options.baseDelay || 1000;
this.retryCount = 0;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('Connected');
this.retryCount = 0;
this.onopen?.();
};
this.ws.onclose = (event) => {
if (!event.wasClean) {
this.reconnect();
}
this.onclose?.(event);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
// onerror is followed by onclose, so reconnection happens there
};
this.ws.onmessage = (event) => {
this.onmessage?.(event);
};
}
reconnect() {
if (this.retryCount >= this.maxRetries) {
console.error('Max retries reached');
this.onmaxretries?.();
return;
}
const delay = this.getBackoffDelay();
console.log(`Reconnecting in ${delay}ms (attempt ${this.retryCount + 1})`);
setTimeout(() => {
this.retryCount++;
this.connect();
}, delay);
}
getBackoffDelay() {
// Exponential backoff with full jitter
const exponentialDelay = Math.min(
this.baseDelay * Math.pow(2, this.retryCount),
this.maxDelay
);
return Math.random() * exponentialDelay;
}
send(data) {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(data);
} else {
console.warn('Cannot send, not connected');
}
}
close() {
this.maxRetries = 0;
this.ws?.close();
}
}
// Usage
const ws = new ReconnectingWebSocket('wss://server.example.com/ws', {
maxRetries: 10,
baseDelay: 500,
maxDelay: 15000,
});
ws.onmessage = (event) => {
console.log('Received:', event.data);
};
ws.onmaxretries = () => {
console.log('Showing offline message to user');
};
Expected output: Client automatically reconnects with exponential backoff, giving up after 10 attempts.
Example 2: Reconnection with Message Queue
class QueuedReconnectingWebSocket {
constructor(url) {
this.url = url;
this.messageQueue = [];
this.isConnected = false;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
this.isConnected = true;
this.flushQueue();
this.onopen?.();
};
this.ws.onclose = () => {
this.isConnected = false;
setTimeout(() => this.connect(), this.getBackoffDelay());
};
}
flushQueue() {
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
this.ws.send(message);
}
}
send(data) {
if (this.isConnected) {
this.ws.send(data);
} else {
this.messageQueue.push(data);
console.log('Queued message for later delivery');
}
}
getBackoffDelay() {
return 1000 + Math.random() * 4000;
}
}
// Usage with message tracking
const ws = new QueuedReconnectingWebSocket('wss://server.example.com/ws');
// These messages will be queued if not connected
ws.send(JSON.stringify({ type: 'join', room: 'general' }));
ws.send(JSON.stringify({ type: 'message', text: 'Hello' }));
ws.onopen = () => {
console.log('Connected! Queued messages flushed.');
};
Expected output: Messages sent while disconnected are queued and automatically sent when the connection is restored.
Example 3: Socket.IO Reconnection Configuration
const { io } = require('socket.io-client');
const socket = io('wss://server.example.com', {
// Reconnection options
reconnection: true,
reconnectionAttempts: 20,
reconnectionDelay: 1000,
reconnectionDelayMax: 30000,
randomizationFactor: 0.5,
// Connection options
timeout: 20000,
transports: ['websocket', 'polling'],
// Auth with reconnection
auth: (cb) => {
cb({
token: getLatestToken(),
});
},
});
// Reconnection event handlers
socket.on('connect', () => {
console.log('Connected with ID:', socket.id);
// Re-subscribe to rooms
socket.emit('subscribe', { room: 'updates' });
});
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
if (reason === 'io server disconnect') {
// Server initiated disconnect, do not reconnect
socket.connect();
}
});
socket.on('reconnect_attempt', (attemptNumber) => {
console.log(`Reconnection attempt ${attemptNumber}`);
});
socket.on('reconnect_error', (error) => {
console.error('Reconnection error:', error.message);
});
socket.on('reconnect_failed', () => {
console.error('All reconnection attempts failed');
showOfflineBanner();
});
// Track connection state
socket.on('reconnect', () => {
console.log('Successfully reconnected');
restoreApplicationState();
});
Expected output: Socket.IO handles reconnection automatically with configurable backoff, auth token refresh, and state restoration.
Common Mistakes
| Mistake | Explanation |
|---|---|
| Using fixed reconnection intervals | Fixed intervals cause thundering herds when servers restart; use exponential backoff with jitter |
| Not limiting reconnection attempts | Infinite reconnection attempts without limit can drain battery and bandwidth |
| Forgetting to handle auth token expiry | Tokens may expire during long disconnections; refresh auth on reconnect |
| Not queuing messages during disconnection | Messages sent while disconnected are lost unless queued |
| Ignoring connection state in UI | Users should see connection status indicators so they know when offline |
Practice Questions
- What is exponential backoff and why is it used for reconnection?
- How does jitter prevent thundering herd problems?
- How do you handle message delivery guarantees during reconnection?
- What is the difference between clean and unclean disconnections?
- How does Socket.IO handle reconnection differently from raw WebSocket?
Challenge
Build a WebSocket client with a state machine that tracks connection states (connecting, connected, disconnected, reconnecting, waiting). Implement exponential backoff with jitter, message queuing, and a UI indicator showing connection status. Include auth token refresh on reconnection.
FAQ
Mini Project
Build a WebSocket client SDK with advanced reconnection features: adaptive backoff that adjusts based on network conditions, message replay with deduplication, session restoration, and a connection status widget. Include integration with a real chat application.
What's Next
Learn about WebSocket heartbeats and keep-alive
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro