Redis Client

Factory that wraps ioredis with lifecycle management. All Redis extensions accept this client.

// src/lib/server/redis.js
import { createRedisClient } from 'svelte-adapter-uws-extensions/redis';

export const redis = createRedisClient({
  url: 'redis://localhost:6379',
  keyPrefix: 'myapp:'   // optional, prefixes all keys
});

Options

OptionDefaultDescription
url'redis://localhost:6379'Redis connection URL
keyPrefix''Prefix for all keys
autoShutdowntrueDisconnect on sveltekit:shutdown
options{}Extra ioredis options

API

MethodDescription
redis.redisThe underlying ioredis instance
redis.key(k)Returns keyPrefix + k
redis.duplicate(overrides?)New connection with same config. Pass ioredis options to override defaults.
redis.quit()Gracefully disconnect all connections

Pub/Sub Bus

Distributes platform.publish() calls across multiple server instances via Redis pub/sub. Each instance publishes locally AND to Redis. Incoming Redis messages are forwarded to the local platform with echo suppression (keyed by a per-process instance ID, so messages originating from the same instance are dropped on receive).

Multiple publish() calls within the same event-loop tick are coalesced into a single Redis pipeline via microtask batching. This means a form action that publishes to three topics results in one pipelined round trip, not three independent commands.

When to use over the built-in plugin: The core adapter’s platform.publish() only reaches clients connected to the current process. If you run two or more instances behind a load balancer, clients on instance A will not see messages published on instance B. The pub/sub bus fixes that.

Setup

// src/lib/server/bus.js
import { redis } from './redis.js';
import { createPubSubBus } from 'svelte-adapter-uws-extensions/redis/pubsub';

export const bus = createPubSubBus(redis);

Usage

The recommended wiring is bus.hooks.open - a ready-made hook that does both the subscriber activation and the per-connection systemChannel subscribe in one step:

// src/hooks.ws.js
import { bus } from '$lib/server/bus';
import { createMessage } from 'svelte-realtime/server';

export const { open } = bus.hooks;

export const message = createMessage({
  platform: (platform) => bus.wrap(platform)
});

bus.hooks.open puts every connection in the systemChannel subscriber set via platform.subscribe(ws, '__realtime') (the platform-trust path, which intentionally bypasses the wire-level __-prefix gate) AND calls bus.activate(platform) on first invocation. This is the one-line wiring; the previous two-line pattern (bus.activate(platform) + manual subscribe) still works but is no longer recommended.

The auto-systemChannel subscribe matters because, since svelte-adapter-uws@0.5, wire-level subscribes to __-prefixed topics are denied. Pre-rename, the client-side store’s wire subscribe to __realtime was the side-effect that populated the subscriber set server-side; after the wire gate, nothing else was putting connections into the systemChannel subscriber set. Without bus.hooks.open, bus-emitted degraded / recovered frames publish into an empty set and $health === 'degraded' is silently dead.

The lower-level pattern, if you need to compose with other open-time work:

// src/hooks.ws.js
import { bus } from '$lib/server/bus';

let distributed;

export function open(ws, { platform }) {
  bus.activate(platform);             // start subscriber (idempotent)
  bus.hooks.open(ws, { platform });   // subscribe ws to systemChannel
  distributed = bus.wrap(platform);
}

export function message(ws, { data, platform }) {
  const msg = JSON.parse(Buffer.from(data).toString());
  distributed.publish('chat', 'message', msg);
}

Mirrors the bus.hooks surface already exposed by createShardedBus.

Options

OptionDefaultDescription
channel'uws:pubsub'Redis channel name
maxEnvelopeBytes1_048_576 (1 MB)Inbound envelope size cap. Larger envelopes are rejected before JSON.parse.
allowSystemTopicsfalseWhether to republish __-prefixed topics. The configured systemChannel is always allowlisted.
systemChannel'__realtime'Bus’s own degraded/recovered system topic. Set null or false to disable auto-emission.
onDegraded / onRecoveredunsetOptional local callbacks for circuit-breaker state changes.

Upgrading from 0.4.x: allowSystemTopics defaults to false in 0.5. If your app legitimately bus-relays user-defined __-prefixed topics, set allowSystemTopics: true explicitly. Pre-fix, the bus relayed any topic the wire layer accepted.

API

MethodDescription
bus.wrap(platform)Returns a wrapped Platform whose publish / publishBatched route through Redis + local. Also passes through subscribe, unsubscribe, checkSubscribe, sendCoalesced, request, requestId, pressure, onPressure, onPublishRate, maxPayloadLength, bufferedAmount, replay (live getter, so platform.replay = ... set after the wrap is visible to framework auto-routing).
bus.hooks.openReady-made open hook. Calls bus.activate(platform) (idempotent) and subscribes the connection to systemChannel via platform.subscribe. Drop in as export const { open } = bus.hooks.
bus.activate(platform)Start the Redis subscriber (idempotent).
bus.deactivate()Stop the subscriber.
bus.publishBatched(messages)One Redis envelope per call (one PUBLISH for createPubSubBus, one SPUBLISH per shard for createShardedBus). Receivers fan out via platform.publishBatched.

degraded / recovered events

When createPubSubBus shares a circuit breaker with the rest of the extensions, the bus auto-emits degraded / recovered events on the configured systemChannel. Counters: pubsub_degraded_total, pubsub_recovered_total. Replaces the manually wired breaker.onStateChange to __system topic pattern from 0.4.x docs.

Parse-error counter

Malformed Redis envelopes increment pubsub_parse_errors_total (sharded_pubsub_parse_errors_total for createShardedBus). Pre-0.5 they were silently swallowed.

ConnectionError redaction

When createRedisClient throws on DNS / TLS / malformed-URL, the ConnectionError message redacts the password segment to ***. Error-tracker hooks searching for the raw connection string must update queries; the redacted form is redis://:***@host:port. The helper is exported standalone via svelte-adapter-uws-extensions/sensitive.

See also

Was this page helpful?