Lifecycle Hooks

Two optional hooks in src/hooks.ws.js cover once-per-worker setup and teardown:

HookWhen it firesUse for
init({ platform })Once per worker after the listen socket is bound, before any upgrade / open / message.Capture platform, register cron platform, wire push registry, warm caches.
shutdown({ platform })Once per worker before the listen socket closes.Flush metrics, close DB / Redis clients, write final state.

Both are async-allowed and awaited. start() (production) and createTestServer() (test harness) resolve only after init completes; a throwing init rejects the promise. Throwing shutdown is logged and ignored - shutdown should be best-effort.

Basic usage

// src/hooks.ws.js
import { live, message, close, unsubscribe, setCronPlatform } from 'svelte-realtime/server';

let metrics;

export async function init({ platform }) {
  setCronPlatform(platform);
  metrics = await connectMetrics();
}

export async function shutdown() {
  await metrics?.flush();
  await metrics?.close();
}

export { message, close, unsubscribe };

Why init exists

Pre-0.5, setCronPlatform, live.configurePush({ remoteRegistry }), and other framework-level setup happened from the open(ws, platform) hook on the first connection. There was a boot-to-first-connect window where:

  • Cron ticks fired into a no-op platform.
  • live.push(userId, ...) could not reach cross-instance users because the registry had not been wired.
  • init-shaped work in user code (DB pools, cache warm-up, leader election) had to be fudged into open and gated by a “first-call” boolean.

init fires before any of that and is awaited by the listen socket bind. By the time the server starts accepting upgrades, every once-per-worker primitive is in place.

Cluster fan-out

In clustered deployments, each worker fires its own init. If you need cluster-wide singleton semantics (one leader per group, single source of cron), layer leader election on top:

import { createLeader } from 'svelte-adapter-uws-extensions/redis/leader';
import { configureCron } from 'svelte-realtime/server';

let leader;

export async function init({ platform }) {
  leader = await createLeader(redis, { key: 'cron-leader' });
  configureCron({
    leader: () => leader.isLeader(),
    bus
  });
}

export async function shutdown() {
  await leader?.stop();
}

See createLeader and the Cron docs for the full pattern.

Adapter requirement

init and shutdown require svelte-adapter-uws@^0.5.0. On 0.4 adapters the hooks are silently ignored; the legacy “first connect” pattern continues to work.

Push registry wiring

Migrate live.configurePush from open to init:

- export function open(ws, { platform }) {
-   live.configurePush({ remoteRegistry: registry });
- }
+ export function init({ platform }) {
+   live.configurePush({ remoteRegistry: registry });
+ }

live.configurePush accepts identify and remoteRegistry independently (one is required). Passing neither throws.

Was this page helpful?