home / skills / secondsky / claude-skills / websocket-implementation

This skill implements scalable real-time messaging with room-based WebSocket support, offering authentication, Redis-backed scaling, and reliable delivery for

npx playbooks add skill secondsky/claude-skills --skill websocket-implementation

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
6.1 KB
---
name: websocket-implementation
description: Implements real-time WebSocket communication with connection management, room-based messaging, and horizontal scaling. Use when building chat systems, live notifications, collaborative tools, or real-time dashboards.
---

# WebSocket Implementation

Build scalable real-time communication systems with proper connection management.

## Server Implementation (Socket.IO)

```javascript
const { Server } = require('socket.io');
const { createAdapter } = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const io = new Server(server, {
  cors: { origin: process.env.CLIENT_URL, credentials: true }
});

// Redis adapter for horizontal scaling
const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.adapter(createAdapter(pubClient, subClient));
});

// Connection management
const users = new Map();

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  try {
    socket.user = verifyToken(token);
    next();
  } catch (err) {
    next(new Error('Authentication failed'));
  }
});

io.on('connection', (socket) => {
  users.set(socket.user.id, socket.id);
  console.log(`User ${socket.user.id} connected`);

  socket.on('join-room', (roomId) => {
    socket.join(roomId);
    socket.to(roomId).emit('user-joined', socket.user);
  });

  socket.on('message', ({ roomId, content }) => {
    io.to(roomId).emit('message', {
      userId: socket.user.id,
      content,
      timestamp: Date.now()
    });
  });

  socket.on('disconnect', () => {
    users.delete(socket.user.id);
  });
});

// Utility methods for message distribution
function broadcastUserUpdate(userId, data) {
  io.to(`user:${userId}`).emit('user-update', data);
}

function notifyRoom(roomId, event, data) {
  io.to(`room:${roomId}`).emit(event, data);
}

function sendDirectMessage(userId, message) {
  const socketId = users.get(userId);
  if (socketId) {
    io.to(socketId).emit('direct-message', message);
  }
}
```

## Client Implementation

```javascript
import { io } from 'socket.io-client';

class WebSocketClient {
  constructor(url, token) {
    this.socket = io(url, {
      auth: { token },
      reconnection: true,
      reconnectionDelay: 1000,
      reconnectionAttempts: 5
    });

    this.messageQueue = [];
    this.setupListeners();
  }

  setupListeners() {
    this.socket.on('connect', () => {
      console.log('Connected');
      this.flushQueue();
    });

    this.socket.on('disconnect', (reason) => {
      console.log('Disconnected:', reason);
    });

    this.socket.on('message', (msg) => {
      this.onMessage?.(msg);
    });
  }

  joinRoom(roomId) {
    this.socket.emit('join-room', roomId);
  }

  send(roomId, content) {
    if (this.socket.connected) {
      this.socket.emit('message', { roomId, content });
    } else {
      this.messageQueue.push({ roomId, content });
    }
  }

  flushQueue() {
    while (this.messageQueue.length > 0) {
      const msg = this.messageQueue.shift();
      this.socket.emit('message', msg);
    }
  }
}
```

## React Hook

```javascript
function useWebSocket(url) {
  const [socket, setSocket] = useState(null);
  const [connected, setConnected] = useState(false);
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    // getToken() is a user-supplied helper that returns the current auth token
    // Example implementations:
    // - From localStorage: () => localStorage.getItem('authToken')
    // - From context: () => authContext.token
    // - From cookie: () => document.cookie.split('token=')[1]
    const ws = io(url, { auth: { token: getToken() } });

    ws.on('connect', () => setConnected(true));
    ws.on('disconnect', () => setConnected(false));
    ws.on('message', (msg) => {
      setMessages(prev => [...prev, msg]);
    });

    setSocket(ws);
    return () => ws.disconnect();
  }, [url]);

  const send = useCallback((roomId, content) => {
    socket?.emit('message', { roomId, content });
  }, [socket]);

  return { connected, messages, send };
}
```

## Message Protocol

```typescript
interface Message {
  type: 'message' | 'typing' | 'presence';
  roomId: string;
  userId: string;
  content?: string;
  timestamp: number;
}

// Acknowledge delivery
socket.emit('message', data, (ack) => {
  if (ack.success) console.log('Delivered');
});
```

## Additional Implementations

See [references/python-websocket.md](references/python-websocket.md) for:
- Python aiohttp WebSocket server
- FastAPI WebSocket endpoints
- Async connection handling

## Scaling Considerations

| Connections | Architecture |
|-------------|--------------|
| <10K | Single server |
| 10K-100K | Redis pub/sub |
| >100K | Sharded Redis + load balancer |

## Monitoring Endpoints

```javascript
// Express endpoints for operational visibility
app.get('/api/ws/stats', (req, res) => {
  res.json({
    activeConnections: io.sockets.sockets.size,
    rooms: [...io.sockets.adapter.rooms.keys()],
    users: users.size
  });
});

app.get('/api/ws/health', (req, res) => {
  res.json({
    status: 'healthy',
    uptime: process.uptime(),
    memoryUsage: process.memoryUsage()
  });
});
```

## Best Practices

- Authenticate before allowing operations
- Implement reconnection with exponential backoff
- Use rooms and channels for targeted broadcasting
- Add heartbeat/ping for connection health
- Persist important messages to database
- Monitor active connection counts
- Display user presence/availability status
- Implement rate limiting on incoming messages
- Use acknowledgments to confirm message delivery
- Leverage Redis for distributed deployments
- Implement comprehensive error handling

## Never Do

- Send sensitive data unencrypted
- Store unlimited messages in memory
- Skip authorization on room joins
- Ignore connection error handling
- Allow unbounded room subscriptions
- Neglect cleanup of disconnected user data
- Send frequent oversized message payloads
- Include authentication credentials in message bodies
- Deploy without security validation
- Allow uncontrolled connection accumulation
- Build without scalability consideration

Overview

This skill implements production-ready real-time WebSocket communication with connection management, room-based messaging, and horizontal scaling. It provides server and client patterns, a React hook, monitoring endpoints, and a clear message protocol to build chat, notifications, and collaborative tools. The implementation focuses on authentication, reliability, and scale using Redis adapters and monitoring utilities.

How this skill works

The server uses Socket.IO with a Redis adapter for pub/sub to enable horizontal scaling and shared room state across instances. Connections are authenticated during the handshake, tracked in an in-memory map, and routed into rooms for targeted broadcasts. The client provides reconnection, message queuing, and flush-on-connect behavior; a React hook wraps the client for easy integration into components. Monitoring endpoints expose active connections, rooms, and health metrics for operational visibility.

When to use it

  • Building chat systems with multiple rooms and direct messages
  • Delivering live notifications or presence updates to users
  • Collaborative editors or dashboards requiring low-latency updates
  • Scaling real-time traffic across multiple server instances
  • When you need built-in reconnection, message acknowledgment, and queueing

Best practices

  • Authenticate sockets on handshake and enforce authorization for room joins
  • Use Redis adapter (or sharded Redis) to scale beyond a single server
  • Implement reconnection with exponential backoff and client-side message queueing
  • Persist important messages to a database; avoid storing unlimited state in memory
  • Expose health and stats endpoints for monitoring and capacity planning
  • Rate limit incoming messages and use acknowledgments for delivery guarantees

Example use cases

  • Multi-room chat with presence indicators and direct messaging
  • Real-time collaboration where edits broadcast to room participants
  • Live dashboards that push metrics and alerts to subscribed clients
  • Notification service that targets users or groups across many servers
  • Gaming lobbies where join/leave events and game state are synchronized

FAQ

How does horizontal scaling work?

Use a Redis adapter to share events and room state across instances; for very high scale, shard Redis and use a load balancer.

How are disconnected users handled?

Track active sockets in a server-side map and clean up on disconnect; consider heartbeats and timeouts to detect stale sessions.