Helios

Lifecycle and ownership

start, stop, close, and who owns transports and stores.

Lifecycle

CallEffect
First mutation or start()Restore persisted targets (once), start scheduler
stop()Pause scheduling; keep in-memory and stored targets
close()Drain work, stop, run onClose, close owned deps

close() is idempotent. After stop(), the next mutation auto-starts again without reloading the store. Calling start() while already running is safe.

await source.start();
await source.stop();
await source.close();

Hooks onStart, onStop, and onClose run during those transitions. A hook failure fails the lifecycle call.

Ownership

By default:

  • Injected transports, receivers, and stores stay caller-owned
  • The default memory store is source-owned
  • createSacnSource from @helioslx/core/node owns its transport
  • Redis stores own clients they create from url; injected clients are caller-owned unless closeClient: true

Transfer ownership explicitly:

const source = createSacnSource({
  transport,
  store,
  ownsTransport: true,
  ownsStore: true,
});

The HTTP adapter owns neither the source nor the viewer.

Process signals (Node)

createSacnSource from @helioslx/core/node registers the source and, unless you pass installProcessHandlers: false, installs process-wide SIGINT, SIGTERM, and beforeExit handlers once. Those handlers close every registered Node source.

Opt out when the host application already owns signal handling:

const source = createSacnSource({
  name: "Host-managed",
  installProcessHandlers: false,
});

Shutdown timing

shutdownTimeoutMs (default 2000) bounds owned transport shutdown. Bound your own process exit separately — an unawaited mutation can still be in flight when the process dies.

close() stops package output. It does not guarantee a safe physical state on fixtures. Configure receiver source-loss behavior, and send a deliberate blackout if your venue requires it. See Safety.

On this page