websocket-patterns
Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.
Best use case
websocket-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.
Teams using websocket-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/websocket-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How websocket-patterns Compares
| Feature / Agent | websocket-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# WebSocket Patterns
Production WebSocket patterns for real-time applications.
## Connection Management
```typescript
import { WebSocketServer, WebSocket } from 'ws'
interface Client {
id: string
ws: WebSocket
rooms: Set<string>
lastPing: number
metadata: Record<string, unknown>
}
class ConnectionManager {
private clients = new Map<string, Client>()
private heartbeatInterval: NodeJS.Timeout
constructor(private wss: WebSocketServer) {
this.heartbeatInterval = setInterval(() => this.checkHeartbeats(), 30_000)
wss.on('connection', (ws, req) => {
const clientId = crypto.randomUUID()
const client: Client = {
id: clientId,
ws,
rooms: new Set(),
lastPing: Date.now(),
metadata: { ip: req.socket.remoteAddress }
}
this.clients.set(clientId, client)
ws.on('pong', () => { client.lastPing = Date.now() })
ws.on('close', () => this.removeClient(clientId))
ws.on('error', () => this.removeClient(clientId))
this.send(client, { type: 'connected', clientId })
})
}
private checkHeartbeats(): void {
const staleThreshold = Date.now() - 45_000
for (const [id, client] of this.clients) {
if (client.lastPing < staleThreshold) {
client.ws.terminate()
this.removeClient(id)
} else {
client.ws.ping()
}
}
}
private removeClient(id: string): void {
const client = this.clients.get(id)
if (!client) return
for (const room of client.rooms) {
this.leaveRoom(id, room)
}
this.clients.delete(id)
}
send(client: Client, data: unknown): void {
if (client.ws.readyState === WebSocket.OPEN) {
client.ws.send(JSON.stringify(data))
}
}
destroy(): void {
clearInterval(this.heartbeatInterval)
}
}
```
## Room Pattern
```typescript
class RoomManager {
private rooms = new Map<string, Set<string>>()
joinRoom(clientId: string, room: string): void {
if (!this.rooms.has(room)) {
this.rooms.set(room, new Set())
}
this.rooms.get(room)!.add(clientId)
}
leaveRoom(clientId: string, room: string): void {
const members = this.rooms.get(room)
if (!members) return
members.delete(clientId)
if (members.size === 0) this.rooms.delete(room)
}
broadcast(room: string, data: unknown, excludeId?: string): void {
const members = this.rooms.get(room)
if (!members) return
const payload = JSON.stringify(data)
for (const id of members) {
if (id === excludeId) continue
const client = this.clients.get(id)
if (client?.ws.readyState === WebSocket.OPEN) {
client.ws.send(payload)
}
}
}
getRoomSize(room: string): number {
return this.rooms.get(room)?.size ?? 0
}
}
```
## Client-Side Reconnection
```typescript
class ReconnectingWebSocket {
private ws: WebSocket | null = null
private reconnectAttempts = 0
private maxReconnectDelay = 30_000
private messageBuffer: unknown[] = []
private handlers = new Map<string, Function[]>()
constructor(private url: string) {
this.connect()
}
private connect(): void {
this.ws = new WebSocket(this.url)
this.ws.onopen = () => {
this.reconnectAttempts = 0
this.flushBuffer()
this.emit('connected')
}
this.ws.onclose = (event) => {
if (event.code === 1000) return // Normal closure, no reconnect
this.scheduleReconnect()
}
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data as string)
this.emit(data.type, data)
}
this.ws.onerror = () => {
this.ws?.close()
}
}
private scheduleReconnect(): void {
// Exponential backoff with jitter
const baseDelay = Math.min(1000 * 2 ** this.reconnectAttempts, this.maxReconnectDelay)
const jitter = baseDelay * 0.3 * Math.random()
const delay = baseDelay + jitter
this.reconnectAttempts++
setTimeout(() => this.connect(), delay)
}
send(data: unknown): void {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data))
} else {
// Buffer messages while disconnected (max 100)
if (this.messageBuffer.length < 100) {
this.messageBuffer.push(data)
}
}
}
private flushBuffer(): void {
const buffered = [...this.messageBuffer]
this.messageBuffer = []
for (const msg of buffered) {
this.send(msg)
}
}
on(event: string, handler: Function): void {
if (!this.handlers.has(event)) this.handlers.set(event, [])
this.handlers.get(event)!.push(handler)
}
private emit(event: string, ...args: unknown[]): void {
for (const handler of this.handlers.get(event) ?? []) {
handler(...args)
}
}
}
```
## Message Protocol Design
```typescript
// Typed message envelope
interface WsMessage<T = unknown> {
type: string
id: string // For request-response correlation
timestamp: number
payload: T
}
// Request-response over WebSocket
class WsRpc {
private pending = new Map<string, { resolve: Function; timer: NodeJS.Timeout }>()
async request<T>(type: string, payload: unknown, timeoutMs = 5000): Promise<T> {
const id = crypto.randomUUID()
const msg: WsMessage = { type, id, timestamp: Date.now(), payload }
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.pending.delete(id)
reject(new Error(`RPC timeout: ${type}`))
}, timeoutMs)
this.pending.set(id, { resolve, timer })
this.ws.send(JSON.stringify(msg))
})
}
handleResponse(msg: WsMessage): void {
const entry = this.pending.get(msg.id)
if (!entry) return
clearTimeout(entry.timer)
this.pending.delete(msg.id)
entry.resolve(msg.payload)
}
}
```
## Checklist
- [ ] Heartbeat/ping-pong every 30s, terminate stale connections at 45s
- [ ] Exponential backoff with jitter for client reconnection (1s-30s)
- [ ] Message buffer during disconnection (cap at 100 messages)
- [ ] Auth token validation on initial handshake (not in messages)
- [ ] Room-based broadcasting for scoped message delivery
- [ ] Rate limit per client (max messages/second)
- [ ] Message size limit (max 1MB per frame)
- [ ] Graceful shutdown: close code 1001, drain messages before exit
## Anti-Patterns
- No heartbeat: zombie connections consuming resources
- Reconnecting without backoff: hammering server on outage
- Unbounded message buffer: memory leak during long disconnections
- Auth in every message: use connection-level auth, not per-message
- Broadcasting to all clients when only a room subset needs the update
- Synchronous JSON.parse in hot path: use worker threads for heavy payloadsRelated Skills
vector-db-patterns
Embedding strategies, ANN algorithms, hybrid search, RAG chunking strategies, and reranking for semantic search and retrieval.
tracing-patterns
OpenTelemetry setup, span context propagation, sampling strategies, Jaeger queries
terraform-patterns
Module composition, state management, workspace strategy, provider versioning, and infrastructure-as-code best practices.
swift-patterns
SwiftUI view composition, @Observable patterns, async/await concurrency, TCA architecture, and Combine reactive streams.
springboot-patterns
Spring Boot architecture patterns, REST API design, layered services, data access, caching, async processing, and logging. Use for Java Spring Boot backend work.
seo-patterns
Meta tag patterns, structured data (JSON-LD), Core Web Vitals optimization, and SSR/SSG strategies for search visibility.
secret-patterns
30+ service-specific secret detection regex patterns, entropy-based detection, PEM/JWT/Base64 identification, and false positive filtering.
saas-payment-patterns
Payment provider abstraction, webhook security, subscription lifecycle, dunning flows, pricing models, invoicing, tax handling, and refund patterns for SaaS applications.
saas-auth-patterns
SaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling.
saas-analytics-patterns
SaaS analytics event taxonomy, metric formulas (MRR, churn, LTV), provider-agnostic tracking, funnel analysis, cohort setup, and privacy-respecting instrumentation.
revenuecat-patterns
RevenueCat SDK entegrasyon pattern'leri. iOS (Swift), Android (Kotlin), React Native ve Flutter icin setup, offerings, entitlement checking, webhook integration, StoreKit 2 migration ve sandbox testing.
resilience-patterns
Circuit breaker, bulkhead, retry with jitter, graceful shutdown, health check patterns for production resilience.