Skip to main content

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 required roomId query parameter:
For production deployments using WSS:

Connection Parameters

Room ID Validation

Room IDs must meet the following criteria:
  • Pattern: /^[A-Za-z0-9_\-:.]+$/
  • Length: 1 to roomIdMaxLength characters (default: 128)
  • Type: String
Example valid room IDs:

Connection Lifecycle

1. WebSocket Handshake

When a client connects, the server performs the following checks:
  1. Circuit breaker check - Rejects connections if Redis is unavailable
  2. Room ID validation - Verifies format and length
  3. Origin validation - Checks against allowed origins (if configured)
  4. Subprotocol validation - Verifies required subprotocol (if configured)
  5. JWT authentication - Validates token and room access (if enabled)
  6. Rate limiting - Enforces connection rate limits per IP
  7. Room capacity - Ensures room is not full
Successful connection:

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:
  1. Client removed from local room map
  2. Client removed from Redis room set: SREM room:ROOM_ID clientId
  3. Expiry set on room: EXPIRE room:ROOM_ID roomTtlSeconds
  4. peer-disconnected message broadcast to remaining peers
  5. Heartbeat interval cleared

Room-Based Routing

The server organizes connections into rooms, each identified by a unique roomId.

Room Structure

Local in-memory map:
Redis distributed set:

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

  1. Server subscribes to room:* pattern on startup
  2. On receiving a message:
    • Parses JSON payload
    • Filters out messages from same server instance (via originServerId)
    • Forwards data to all local clients in the room (except sender)

Atomic Room Operations

The server uses Lua scripts for atomic Redis operations: Join operation:
Leave 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
Open (Failure):
  • Redis operations fail cbErrorThreshold times (default: 3)
  • Circuit opens for cbOpenMs milliseconds (default: 30000)
  • New connections rejected with code 1013 (“Service unavailable”)
  • Existing connections continue with local-only forwarding
Half-Open (Recovery):
  • 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: rateLimitConnPer10s connections per 10 seconds (default: 5)
  • Action: Close with code 1013 (“Rate limited”)

Message Rate Limits

Per-client token bucket:
  • Limit: rateLimitMessagesPer10s messages per 10 seconds (default: 100)
  • Refill: Continuous token bucket algorithm
  • Action: Drop message silently
Per-IP message rate:
  • Namespace: msg-ip
  • Key: Client IP address
  • Limit: rateLimitIpMsgsPer10s per 10 seconds (default: 500)
Per-room message rate:
  • Namespace: msg-room
  • Key: Room ID
  • Limit: rateLimitRoomMsgsPer10s per 10 seconds (default: 1000)

Backpressure Management

The server monitors WebSocket.bufferedAmount to prevent memory exhaustion:
Default threshold: 1MB (configurable)

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:
  1. Enter drain mode (reject new connections)
  2. Close WebSocket server
  3. Send close frames to all clients with code 1001 (“Going away”)
  4. Clean up Redis room membership
  5. Publish peer-disconnected messages
  6. Wait up to drainTimeoutMs for graceful close
  7. Disconnect from Redis
  8. Exit process

Error Handling

Connection Errors

Message Validation Errors

Invalid messages trigger a control error response:
The invalid message is dropped and not forwarded.

Security Features

JWT Authentication

When enableAuth is configured:
Token validation:
  • 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:
Connections from unlisted origins are rejected.

Message Size Limits

Maximum message size enforced:
Oversized messages are dropped silently.

Configuration Reference