Overview
socket-serve is designed to bring WebSocket-like real-time functionality to serverless environments where traditional persistent connections aren’t possible. It achieves this through a clever combination of HTTP-based transports and Redis for state management.High-Level Architecture
Core Components
1. Client SDK (socket-serve/client)
The browser-side SDK that provides a socket.io-like API:
- Automatic reconnection with exponential backoff
- Multiple transport support (SSE, polling)
- Event-based API
- Message acknowledgments
- Connection state management
2. Server Core (socket-serve)
The server-side implementation that runs in your serverless functions:
- Event-driven architecture
- Room-based broadcasting
- Session management
- Message routing
3. Adapters (socket-serve/adapters)
Framework-specific adapters that integrate with your server:
- Next.js Adapter: Creates GET/POST route handlers for App Router
- Express Adapter: Middleware for Express.js applications
4. Redis State Manager
Manages distributed state across serverless instances:Communication Flow
Client → Server
When a client sends a message:- Client calls
socket.emit('event', data) - Client SDK makes HTTP POST to server endpoint
- Server receives message and emits event
- Event handler processes the message
- Response is queued for the client
Server → Client
When a server sends a message:- Server calls
socket.emit('event', data) - Message is stored in Redis queue for that session
- Client’s active connection (SSE/polling) receives message
- Client SDK emits event to application
Transport Mechanisms
Server-Sent Events (SSE)
Primary transport for server → client communication:- Long-lived HTTP GET connection
- One-way: server → client only
- Automatic reconnection built-in to browsers
- Lower latency than polling
HTTP Polling
Fallback transport when SSE isn’t available:- Regular HTTP GET requests (every 1 second)
- Works in all environments
- Higher latency than SSE
- More resource-intensive
State Management
Session State
Each connected client has a session stored in Redis:session:{sessionId}- Session datasession:{sessionId}:rooms- Set of joined roomsroom:{roomName}- Set of sessions in room
Message Queue
Messages are queued in Redis until delivered:messages:{sessionId}- List of pending messagesack:{messageId}- Acknowledgment tracking
Pub/Sub for Broadcasting
Room broadcasting uses Redis pub/sub:Scaling
socket-serve scales horizontally by design:Multiple Serverless Instances
Each serverless function instance:- Connects to shared Redis
- Subscribes to relevant pub/sub channels
- Handles requests independently
- Shares state via Redis
Stateless Functions
No state is stored in serverless functions:- All state in Redis
- Functions can scale to zero
- No sticky sessions needed
- Automatic failover
Reconnection Strategy
Clients automatically reconnect using exponential backoff:- Connection lost detected
- Wait according to backoff schedule
- Attempt reconnection
- If successful: reset counter
- If failed: increment counter and retry
- Give up after 5 attempts (configurable)
Message Acknowledgments
Request/response pattern with timeouts:- Client sends message with unique ID
- Sets 5-second timeout
- Server receives and processes
- Server calls ack callback
- Ack message sent back with same ID
- Client matches ID and calls callback
- Timeout cleared
Performance Characteristics
Latency
- SSE: 50-200ms (depends on network)
- Polling: 1000ms average (1s interval)
- Redis operations: Less than 10ms typically
Throughput
- Limited by Redis performance
- Typical: 10,000+ messages/second
- Scales with Redis cluster size
Resource Usage
Client:- SSE: 1 persistent connection
- Polling: 1 request/second
- Minimal memory footprint
- No persistent connections
- Redis connection pool
- Scales to zero when idle
Comparison with WebSockets
| Aspect | WebSocket | socket-serve |
|---|---|---|
| Connection | Persistent TCP | HTTP-based |
| Serverless | ❌ No | ✅ Yes |
| Bi-directional | ✅ Native | ✅ Via SSE/POST |
| Scaling | Complex | Automatic |
| Latency | Lower (~10-50ms) | Higher (~50-200ms) |
| Compatibility | Some proxies block | Works everywhere |
| State | In-memory | Redis-backed |