Lifecycle Hooks
Two optional hooks in src/hooks.ws.js cover once-per-worker setup and teardown:
| Hook | When it fires | Use 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 intoopenand 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?