Storing presence, channel subscriptions, or message history exclusively in process memory means that restarting a single server instance silently resets that state for all users connected to it. In production, auto-scaling and rolling deploys trigger instance restarts routinely — users are dropped from channels, presence shows them offline, and in-flight message queues are lost. ISO 25010 reliability requires that state survival is not contingent on any individual process's uptime.
Low because in-process-only state loss occurs on restart or scale events — a failure mode that is invisible in development but routine in production deployments.
Externalise real-time state to a shared backend. The Socket.IO Redis adapter handles presence and room membership automatically; use a database or Redis for message history.
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
const pub = createClient({ url: process.env.REDIS_URL });
const sub = pub.duplicate();
await Promise.all([pub.connect(), sub.connect()]);
io.adapter(createAdapter(pub, sub));
// Rooms, presence, and subscription state now survive instance restarts
For message history, write to the database on send and query on reconnect — never rely on an in-process buffer as the source of truth. The skip condition applies only when the deployment contract explicitly states single-instance forever.
ID: community-realtime.realtime-ux.horizontal-scaling-ready
Severity: low
What to look for: Enumerate all real-time state storage locations: in-process Maps, Redis, Memcached, database tables. Count the state types stored externally: presence, message history, subscriptions, channel membership.
Pass criteria: Real-time state (presence, message history, subscriptions) is stored in at least 1 shared backend (Redis, Memcached, database), not only in process memory. At least 2 state types must be externally persisted.
Fail criteria: Real-time state exists only in process memory. Horizontal scaling would lose state when instances restart.
Skip (N/A) when: The deployment is explicitly single-instance and not expected to scale.
Detail on fail: "Presence state stored in process memory only. Adding a second server instance would lose user presence data."
Remediation: Use a shared state backend for horizontal scaling:
import { createAdapter } from '@socket.io-redis';
import { createClient } from 'redis';
const pubClient = createClient();
const subClient = pubClient.duplicate();
io.adapter(createAdapter(pubClient, subClient));
// Now presence, rooms, and other state are shared across instances