Skip to content

feat(observability): RuntimeAddOns trait with a Prometheus add-on#192

Open
mfw78 wants to merge 1 commit into
feat/m0-component-buildersfrom
feat/m0-addons
Open

feat(observability): RuntimeAddOns trait with a Prometheus add-on#192
mfw78 wants to merge 1 commit into
feat/m0-component-buildersfrom
feat/m0-addons

Conversation

@mfw78

@mfw78 mfw78 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #91.

Adds a RuntimeAddOns trait and moves the Prometheus install logic behind it, so an embedder can now choose which add-ons run instead of the runtime hard-coding Prometheus.

This is part of the epic #79 train and merges in stack order: this PR targets feat/m0-component-builders, which itself targets the chain-log PR.

Changes

  • Added crates/nexum-runtime/src/addons.rs with RuntimeAddOns (a single install(&self, ctx: &AddOnsContext<'_>) -> anyhow::Result<AddOnHandle> method), AddOnsContext<'a> (carries the resolved &MetricsSection), AddOnHandle (a name plus an optional guard slot reserved for a future add-on's shutdown handle), and PrometheusAddOn.
  • Moved both original Prometheus install branches into PrometheusAddOn::install unchanged in behaviour: the enabled path calls with_http_listener(addr).install() and logs, the disabled path calls install_recorder() into a discarded sink.
  • bootstrap::run now takes an add_ons: &[&dyn RuntimeAddOns] parameter, installs each add-on before engine boot in the order given, and holds the returned handles until shutdown.
  • Updated the two callers, nexum-cli's launch path and the embed.rs example, to pass [&PrometheusAddOn]. The example comment notes that an embedder can pass &[] to omit add-ons entirely or a different list to replace Prometheus.
  • Exported the new module from nexum-runtime::lib.

Test plan

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo test --workspace --all-features --no-fail-fast (all green, including the supervisor e2e suite)
  • Built all in-tree wasm modules used by the workspace's integration tests
  • embed.rs example builds

Notes for reviewer

The issue text specified the trait and the move but did not specify how an embedder would omit or replace the add-on. I realised that by threading the add-on list into bootstrap::run as a parameter chosen at the composition root, rather than hard-coding a default set inside run. This adds one parameter to run and touches its two callers; there is no behaviour change for the shipped binary, since both callers still pass [&PrometheusAddOn].

AddOnHandle's guard field is public and currently unused by PrometheusAddOn (which manages its own listener task and returns an empty guard). It is the documented seam for a future control-surface add-on to stash a listener or shutdown handle; that add-on is not part of this change.

One known gap: the crate's e2e coverage (shepherd-cow-host) boots via Supervisor::boot_single and never calls bootstrap::run, so no automated test currently exercises the add-ons install path end to end. This is a pre-existing gap in that suite, not something introduced here.

AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.

Move the Prometheus install out of the launch path and into a
PrometheusAddOn behind a RuntimeAddOns trait. install reads the
resolved metrics config from AddOnsContext and preserves the
recorder-versus-listener behaviour: an HTTP listener when enabled,
the recorder alone otherwise so metric call sites stay live.

The launcher takes the add-on list as a parameter, so the composition
root chooses the set and an embedder omits or replaces it. AddOnsContext
and the AddOnHandle guard slot leave room for a future control-surface
add-on.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant