Skip to main content

@hile/reloader

Stabilize config-driven runtime reloads with debounce, singleflight, latest-wins, safe disposal, and multi-source config aggregation.

Choose This Package When

Use When

Use @hile/reloader when runtime config can change frequently and service code needs debounce, singleflight reload, latest-wins behavior, and safe old-runtime preservation.

Do Not Use When

  • Do not use it as a durable queue.
  • Do not use it to restart an HTTP server on the same port; keep the listener stable and reload handlers or runtime state.
  • Do not pass Map, Set, class instances, functions, symbols, circular objects, or sparse arrays to the default comparator; use signature or normalize.
  • Do not rely on timeouts to kill non-cooperative work; timeouts reject the reload path and abort the signal, and late-created runtimes are disposed best-effort.

Install

Imports

Copy-Paste Example

Stable HTTP shell with reloadable runtime:

More Examples

Aggregate multiple micro config topics before reloading:
Manual file watcher:

Runtime And Lifecycle Notes

  • RuntimeReloader.update(input) schedules reload work and settles when the scheduler becomes idle.
  • RuntimeReloader.onStateChange(state) fires when the observable state changes, including status, hasCurrent, and hasPending transitions.
  • During an active reload, a newer update flips hasPending to true; when that pending input is consumed, hasPending flips back to false.
  • If that input starts create() and create() fails, that update() rejects, the old runtime remains current, and the failed input is not marked applied.
  • If an update is superseded before its input starts create(), it settles with the newer pending input because latest-wins coalesced it into that reload.
  • Only one reload runs at a time.
  • Updates during an active reload collapse to the latest pending input.
  • Debounce timers reset while updates arrive before reload starts.
  • create() must succeed before current() switches.
  • After a successful switch, dispose(oldRuntime) runs; dispose failures are reported but do not roll back the new runtime.
  • stop() rejects future updates, aborts an in-flight create() through AbortSignal, clears queued input, and disposes the current runtime.
  • If create() resolves after timeout or abort, that late runtime is not made current and is disposed best-effort.
  • Default compare priority is equals, then signature, then normalize, then an internal stable signature.
  • The internal stable signature is not exported and only supports JSON-like plain config values plus Date and bigint.
  • Default timeouts are 30 seconds for create and 10 seconds for dispose. Override with createTimeoutMs and disposeTimeoutMs.
  • ConfigAggregator.required keys must be explicitly received; defaults do not satisfy required keys.
  • undefined is an explicit received value. Use unset(key) to remove a value and mark the key as not received.
  • ConfigAggregator serializes emits. If values change while listeners are running, the next emit uses the latest snapshot after the current emit finishes.
  • ConfigAggregator records the last emitted signature only after all listeners finish successfully.
  • ConfigAggregator.flush() rejects when a listener fails. Timer-driven emits call onError and leave the signature uncommitted so the same config can retry later.

Anti-Patterns

  • Recreating an HTTP server on the same port for every config change.
  • Letting multiple subscribe callbacks each reload the same runtime independently.
  • Comparing whole runtime objects instead of normalized config.
  • Forgetting to call stop() during application shutdown.

Verification Checklist

  • Burst config updates produce at most one reload per debounce window.
  • A reload failure leaves the previous runtime serving traffic.
  • Multiple required config keys are present before the first reload.
  • HTTP handlers read reloader.current() instead of rebinding the port.
  • onError and onCompareError are connected to logs or metrics.

Stable Runtime Reload

Complete Example

Runtime Dynamic Config

Complete Example

Package-Local AI Guide

This package also ships AI.md in npm so agents can read accurate examples after installation.