ad2a0bd9d0
- Initialize comments.items array in setCommentsTaskId and addComment - Fixes race condition where WebSocket notifications arrived before API call completed
WebSocket Client with Auto-Reconnect
This directory contains the WebSocket client implementation with automatic reconnection capabilities.
Features
1. Automatic Reconnection
- Exponential Backoff: Reconnection delays increase exponentially to avoid overwhelming the server
- Configurable Retry Limits: Set maximum number of reconnection attempts
- Graceful Degradation: Properly handles connection failures and notifies the UI
2. Connection State Management
The client tracks the following connection states:
idle: Initial state before any connection attemptconnecting: Actively establishing a connectionopen: Successfully connected and ready to send/receive messagesreconnecting: Attempting to reconnect after a disconnectclosed: Connection closed (intentionally or after max retries)error: Connection failed and won't retry
3. Message Queue
- Messages sent while disconnected are queued
- Queued messages are automatically sent when connection is restored
- Prevents message loss during brief disconnections
4. Subscription Management
- Tracks task subscriptions across reconnections
- Automatically re-subscribes to all tasks when reconnected
- Provides
subscribe()andunsubscribe()methods for easy subscription management
5. Pending Request Handling
- Properly cleans up pending requests on disconnect
- Rejects pending promises with appropriate error messages
- Prevents memory leaks from abandoned requests
Configuration
Reconnect Options
interface ReconnectOptions {
enabled?: boolean; // Enable/disable auto-reconnect (default: true)
maxAttempts?: number; // Maximum reconnection attempts (default: 10)
initialDelay?: number; // Initial delay in ms (default: 1000)
maxDelay?: number; // Maximum delay in ms (default: 30000)
backoffMultiplier?: number; // Exponential backoff multiplier (default: 1.5)
}
Default Configuration
const DEFAULT_RECONNECT_OPTIONS = {
enabled: true,
maxAttempts: 10,
initialDelay: 1000, // 1 second
maxDelay: 30000, // 30 seconds
backoffMultiplier: 1.5,
};
Usage
Basic Usage
import { WebSocketClient } from '@/lib/ws/client';
const client = new WebSocketClient(
'ws://localhost:8080/ws',
(status) => {
console.log('Connection status:', status);
}
);
client.connect();
Custom Reconnect Configuration
const client = new WebSocketClient(
'ws://localhost:8080/ws',
(status) => {
console.log('Connection status:', status);
},
{
enabled: true,
maxAttempts: 5,
initialDelay: 2000,
maxDelay: 60000,
backoffMultiplier: 2,
}
);
Subscribing to Tasks
// Subscribe to task updates
client.subscribe('task-id-123');
// Unsubscribe when done
client.unsubscribe('task-id-123');
Sending Messages
// Send a message (queued if not connected)
client.send({ type: 'request', action: 'some.action', payload: {} });
// Send a request and wait for response
const response = await client.request('task.get', { id: 'task-123' });
Listening to Events
const unsubscribe = client.on('task.updated', (message) => {
console.log('Task updated:', message.payload);
});
// Clean up when done
unsubscribe();
Reconnection Behavior
Exponential Backoff Example
With default settings:
- Attempt 1: 1 second delay
- Attempt 2: 1.5 seconds delay
- Attempt 3: 2.25 seconds delay
- Attempt 4: 3.375 seconds delay
- ...
- Attempt 10: 30 seconds delay (capped at maxDelay)
What Happens on Disconnect
- Connection closes (network issue, server restart, etc.)
- Client sets status to
closed - If not an intentional disconnect and reconnect is enabled:
- Calculate delay using exponential backoff
- Set status to
reconnecting - Schedule reconnection attempt
- On successful reconnection:
- Reset reconnect attempt counter
- Set status to
open - Flush queued messages
- Re-subscribe to all tasks
- If max attempts reached:
- Set status to
error - Clean up pending requests
- Stop reconnection attempts
- Set status to
Integration with React
The useWebSocket hook automatically sets up the client with reconnection:
import { useWebSocket } from '@/lib/ws/use-websocket';
export function MyComponent() {
const store = useAppStoreApi();
useWebSocket(store, 'ws://localhost:8080/ws');
// Connection status is automatically synced to store
const status = useAppStore((s) => s.connection.status);
return <div>Status: {status}</div>;
}
Testing
To test reconnection behavior:
- Start the application
- Open browser DevTools → Network tab
- Observe WebSocket connection
- Stop the backend server
- Watch the client attempt to reconnect with increasing delays
- Restart the backend server
- Verify the client reconnects and re-subscribes to tasks
Best Practices
- Always use the provided methods: Use
subscribe()/unsubscribe()instead of sending raw messages - Handle connection states in UI: Show appropriate feedback for
connecting,reconnecting, anderrorstates - Clean up subscriptions: Always unsubscribe when components unmount
- Configure appropriately: Adjust reconnect settings based on your use case
- Monitor console logs: Reconnection attempts are logged for debugging