How an addon's new code is brought into a live system — the OCP seam of the hot-reload bridge.
The set of reload strategies is OPEN. Most addons want the default
(:remount: shut down, reconstruct from the manifest, re-initialize, cascade
to dependents), but an addon with particular needs — an open socket it must
drain, a native handle it cannot re-acquire, a stateless dispatcher that only
needs its vars refreshed — supplies its own. So strategies are a PROTOCOL with
a rule chain, never a case over a closed keyword set: closing this set would
be the defect, and adding a strategy must never mean editing this namespace.
Selection, in order:
:addon/reload-strategy <id> gets exactly that
strategy, looked up by id. A declared-but-unregistered id is an error, not
a silent fallback to the default — an addon that asked for special handling
and quietly got generic handling is worse than one that refused.-applies? answers true.
The built-in chain ends in a catch-all, so selection always succeeds.Registration is a var-held chain plus an install seam, mirroring the licence gate in hive-addon.mount.entitlement. Strategies are resolved from the var at CALL time, never captured at wiring time.
Effectful: this is the stratum that shuts addons down and mounts them again.
The namespace-level reloader is INJECTED (:hot/reload-ns!) rather than
required, so hive-hot stays a soft dependency.
How an addon's new code is brought into a live system — the OCP seam of the hot-reload bridge. The set of reload strategies is OPEN. Most addons want the default (`:remount`: shut down, reconstruct from the manifest, re-initialize, cascade to dependents), but an addon with particular needs — an open socket it must drain, a native handle it cannot re-acquire, a stateless dispatcher that only needs its vars refreshed — supplies its own. So strategies are a PROTOCOL with a rule chain, never a `case` over a closed keyword set: closing this set would be the defect, and adding a strategy must never mean editing this namespace. Selection, in order: 1. A spec that DECLARES `:addon/reload-strategy <id>` gets exactly that strategy, looked up by id. A declared-but-unregistered id is an error, not a silent fallback to the default — an addon that asked for special handling and quietly got generic handling is worse than one that refused. 2. Otherwise the first chain member whose `-applies?` answers true. The built-in chain ends in a catch-all, so selection always succeeds. Registration is a var-held chain plus an install seam, mirroring the licence gate in hive-addon.mount.entitlement. Strategies are resolved from the var at CALL time, never captured at wiring time. Effectful: this is the stratum that shuts addons down and mounts them again. The namespace-level reloader is INJECTED (`:hot/reload-ns!`) rather than required, so hive-hot stays a soft dependency.
(default-strategies)A FRESH built-in strategy chain.
Deliberately a function, not a def. Records built at load time and held in a
defonce would keep the class objects of whichever protocol var was current
when they were constructed; reloading this namespace re-mints IReloadStrategy
and those held instances stop satisfying it — the same class-identity failure
this whole namespace exists to prevent, turned on itself. Rebuilding on every
call means the chain always matches the live protocol.
ORDER IS SIGNIFICANT: selection takes the first member whose -applies? is true, and RemountStrategy is the unconditional catch-all, so it stays last. :in-place and :inert never auto-apply — they exist to be NAMED by a spec's :addon/reload-strategy.
A FRESH built-in strategy chain. Deliberately a function, not a def. Records built at load time and held in a `defonce` would keep the class objects of whichever protocol var was current when they were constructed; reloading this namespace re-mints IReloadStrategy and those held instances stop satisfying it — the same class-identity failure this whole namespace exists to prevent, turned on itself. Rebuilding on every call means the chain always matches the live protocol. ORDER IS SIGNIFICANT: selection takes the first member whose -applies? is true, and RemountStrategy is the unconditional catch-all, so it stays last. :in-place and :inert never auto-apply — they exist to be NAMED by a spec's :addon/reload-strategy.
(install-strategies! strategies)Replace the WHOLE chain, built-ins included. Keep a catch-all last or selection can fail. Pass nil to fall back to registered-plus-built-in.
Replace the WHOLE chain, built-ins included. Keep a catch-all last or selection can fail. Pass nil to fall back to registered-plus-built-in.
(installed-strategies)The live strategy chain: module-registered strategies first, then the built-ins, catch-all last. Rebuilt on every call, so a strategy registered after wiring is seen, and a strategy orphaned by a reload is dropped.
The live strategy chain: module-registered strategies first, then the built-ins, catch-all last. Rebuilt on every call, so a strategy registered after wiring is seen, and a strategy orphaned by a reload is dropped.
One way of bringing an addon's new code into a running system.
One way of bringing an addon's new code into a running system.
(-applies? this spec ctx)Should this strategy handle spec given reload context ctx, when the spec
declared no explicit strategy? Chain order decides ties; the built-in
catch-all answers true unconditionally and sits last.
Should this strategy handle `spec` given reload context `ctx`, when the spec declared no explicit strategy? Chain order decides ties; the built-in catch-all answers true unconditionally and sits last.
(-reload! this spec ctx)Perform the reload. Returns a RemountReport map. MUST NOT throw — a failure is folded into the report, because a reload that explodes takes the whole watcher thread with it.
Perform the reload. Returns a RemountReport map. MUST NOT throw — a failure is folded into the report, because a reload that explodes takes the whole watcher thread with it.
(-strategy-id this)Keyword identifying this strategy. What a spec names in
:addon/reload-strategy. Must be stable — it is a manifest-level contract.
Keyword identifying this strategy. What a spec names in `:addon/reload-strategy`. Must be stable — it is a manifest-level contract.
(register-strategy! strategy)Add one strategy, taking precedence over the built-ins. This is the OCP entry point: a module ships its own IReloadStrategy and registers it at load time without this namespace changing.
Replaces any existing registration with the same -strategy-id, so re-running it (as a namespace reload does) is idempotent rather than accumulating duplicates.
Add one strategy, taking precedence over the built-ins. This is the OCP entry point: a module ships its own IReloadStrategy and registers it at load time without this namespace changing. Replaces any existing registration with the same -strategy-id, so re-running it (as a namespace reload does) is idempotent rather than accumulating duplicates.
(reload! spec ctx)Select a strategy for spec and run it. Never throws: a selection failure and
a strategy that blows up both come back as a RemountReport with :ok? false.
Select a strategy for `spec` and run it. Never throws: a selection failure and a strategy that blows up both come back as a RemountReport with :ok? false.
(reset-strategies!)Drop every override and registration, restoring the built-in chain. For tests and for recovering a fouled registry.
Drop every override and registration, restoring the built-in chain. For tests and for recovering a fouled registry.
(select spec ctx)(select spec ctx chain)Choose the strategy for spec under ctx.
Returns (r/ok strategy), or (r/err :hot/unknown-strategy ...) when the spec declared an id nothing in the chain provides. A declared strategy bypasses -applies? entirely: the addon asked for it explicitly.
Choose the strategy for `spec` under `ctx`. Returns (r/ok strategy), or (r/err :hot/unknown-strategy ...) when the spec declared an id nothing in the chain provides. A declared strategy bypasses -applies? entirely: the addon asked for it explicitly.
(strategy-by-id chain sid)Look up a strategy in chain by its id, or nil.
Look up a strategy in `chain` by its id, or nil.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |