Overview
The CloudGaming signaling server uses WebSocket connections to coordinate WebRTC peer connections between hosts and clients. The server implements a scalable, room-based architecture with Redis pub/sub for multi-node deployments.Connection URL
Clients connect to the signaling server using a WebSocket URL with a requiredroomId query parameter:
Connection Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
roomId | string | Yes | Unique room identifier (alphanumeric, _, -, :, .) |
token | string | No | JWT authentication token (if auth enabled) |
Room ID Validation
Room IDs must meet the following criteria:- Pattern:
/^[A-Za-z0-9_\-:.]+$/ - Length: 1 to
roomIdMaxLengthcharacters (default: 128) - Type: String
Connection Lifecycle
1. WebSocket Handshake
When a client connects, the server performs the following checks:- Circuit breaker check - Rejects connections if Redis is unavailable
- Room ID validation - Verifies format and length
- Origin validation - Checks against allowed origins (if configured)
- Subprotocol validation - Verifies required subprotocol (if configured)
- JWT authentication - Validates token and room access (if enabled)
- Rate limiting - Enforces connection rate limits per IP
- Room capacity - Ensures room is not full
2. Active Connection
During an active connection:- Heartbeat: Server sends WebSocket ping frames every
heartbeatIntervalMs(default: 30s) - Pong response: Client must respond with pong frames to maintain connection
- Message forwarding: All messages are forwarded to other peers in the same room
- Local fanout: Messages are delivered to local clients immediately for low latency
- Redis pub/sub: Messages are published to Redis for cross-instance delivery
3. Disconnection
When a client disconnects:- Client removed from local room map
- Client removed from Redis room set:
SREM room:ROOM_ID clientId - Expiry set on room:
EXPIRE room:ROOM_ID roomTtlSeconds peer-disconnectedmessage broadcast to remaining peers- Heartbeat interval cleared
Room-Based Routing
The server organizes connections into rooms, each identified by a uniqueroomId.
Room Structure
Local in-memory map:Message Flow
Room Capacity
Rooms have a configurable maximum capacity (default: 100 clients). When a room is full, new connections receive:Redis Pub/Sub for Multi-Node Scaling
The signaling server uses Redis pub/sub to enable horizontal scaling across multiple server instances.Redis Channels
Each room has a dedicated pub/sub channel:Published Message Format
Subscriber Behavior
- Server subscribes to
room:*pattern on startup - On receiving a message:
- Parses JSON payload
- Filters out messages from same server instance (via
originServerId) - Forwards
datato all local clients in the room (except sender)
Atomic Room Operations
The server uses Lua scripts for atomic Redis operations: Join operation:Circuit Breaker
The server implements a circuit breaker pattern to handle Redis failures gracefully.Circuit States
Closed (Normal):- Redis operations succeed
- Connections accepted
- Messages forwarded
- Redis operations fail
cbErrorThresholdtimes (default: 3) - Circuit opens for
cbOpenMsmilliseconds (default: 30000) - New connections rejected with code 1013 (“Service unavailable”)
- Existing connections continue with local-only forwarding
- After
cbOpenMs, circuit allows test operations - Successful operation closes circuit
- Failed operation re-opens circuit
Rate Limiting
Multiple rate limits protect the server from abuse:Connection Rate Limit
- Namespace:
conn - Key: Client IP address
- Limit:
rateLimitConnPer10sconnections per 10 seconds (default: 5) - Action: Close with code 1013 (“Rate limited”)
Message Rate Limits
Per-client token bucket:- Limit:
rateLimitMessagesPer10smessages per 10 seconds (default: 100) - Refill: Continuous token bucket algorithm
- Action: Drop message silently
- Namespace:
msg-ip - Key: Client IP address
- Limit:
rateLimitIpMsgsPer10sper 10 seconds (default: 500)
- Namespace:
msg-room - Key: Room ID
- Limit:
rateLimitRoomMsgsPer10sper 10 seconds (default: 1000)
Backpressure Management
The server monitorsWebSocket.bufferedAmount to prevent memory exhaustion:
Health and Metrics Endpoints
The server exposes HTTP endpoints on the same port as WebSocket:/healthz
Basic health check:
/readyz
Readiness check with Redis ping:
/metrics
Prometheus-compatible metrics:
Graceful Shutdown
On receiving SIGTERM or SIGINT:- Enter drain mode (reject new connections)
- Close WebSocket server
- Send close frames to all clients with code 1001 (“Going away”)
- Clean up Redis room membership
- Publish
peer-disconnectedmessages - Wait up to
drainTimeoutMsfor graceful close - Disconnect from Redis
- Exit process
Error Handling
Connection Errors
| Code | Reason | Description |
|---|---|---|
| 1008 | Policy Violation | Invalid roomId, missing auth, origin not allowed |
| 1011 | Internal Error | Redis failure during connection |
| 1013 | Service Unavailable | Circuit breaker open, rate limited, backpressure |
| 1000 | Normal Closure | Room full |
Message Validation Errors
Invalid messages trigger a control error response:Security Features
JWT Authentication
WhenenableAuth is configured:
- Verify signature (JWKS or shared secret)
- Check issuer and audience
- Validate room claim:
payload[roomsClaim] - Ensure user authorized for requested room
Origin Validation
Configurable allowed origins:Message Size Limits
Maximum message size enforced:Configuration Reference
| Setting | Default | Description |
|---|---|---|
wsPort | 3002 | WebSocket server port |
redisUrl | localhost:6379 | Redis connection URL |
roomIdMaxLength | 128 | Maximum room ID length |
roomCapacity | 100 | Maximum clients per room |
roomTtlSeconds | 3600 | Room expiry in Redis |
heartbeatIntervalMs | 30000 | Ping interval |
messageMaxBytes | 65536 | Maximum message size |
backpressureCloseThresholdBytes | 1048576 | Buffered amount threshold |
rateLimitConnPer10s | 5 | Connection rate per IP |
rateLimitMessagesPer10s | 100 | Message rate per client |
rateLimitIpMsgsPer10s | 500 | Message rate per IP |
rateLimitRoomMsgsPer10s | 1000 | Message rate per room |
cbErrorThreshold | 3 | Circuit breaker error count |
cbOpenMs | 30000 | Circuit breaker open duration |
drainTimeoutMs | 5000 | Graceful shutdown timeout |
requireWss | false | Enforce WSS in production |
enableAuth | false | Enable JWT authentication |
allowedOrigins | [] | Allowed origin domains |
subprotocol | null | Required WebSocket subprotocol |