Skip to content

chore(deps): bump spawned to 0.6.0 and serve its actor metrics on /metrics - #782

Draft
pablodeymo wants to merge 3 commits into
nightlyfrom
bump-spawned-0.6.0
Draft

pablodeymo wants to merge 3 commits into
nightlyfrom
bump-spawned-0.6.0

Conversation

@pablodeymo

@pablodeymo pablodeymo commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

🗒️ Description / Motivation

spawned v0.6.0 was released on 2026-11-06. It adds actor links, monitors, exit reasons and an opt-in metrics feature, and fixes several shutdown races (idle stop/dispatch ordering, reserved publications at shutdown, monitor waiter retention). This PR moves ethlambda's own actors onto it and turns the metrics feature on, so /metrics reports how the BlockChain and P2P mailboxes behave.

What Changed

Bump (Cargo.toml): spawned-concurrency and spawned-rt 0.5.0 → 0.6.0. Handler and protocol signatures are unchanged, so no actor code moves.

Lockfile: the three spawned crates; windows-* 0.57 → 0.100 (Windows-only targets, inactive here); loom, generator, scoped-tls enter as lock-only entries behind spawned-rt's cfg(spawned_loom) target dependency and never build (cargo tree -i loom finds nothing).

ethrex-p2p v25.0.0 keeps its own spawned 0.5.0. No spawned type crosses that boundary, so both versions coexist.

Metrics (crates/net/rpc): spawned-concurrency gets features = ["metrics"] on the workspace dependency. spawned's collector is separate from the prometheus registry and ships no exporter, so get_metrics appends spawned_concurrency::metrics::render_prometheus() after the registry text. New series on /metrics: spawned_mailbox_depth, spawned_queue_wait_seconds, spawned_handler_duration_seconds, spawned_request_latency_seconds, plus message/handler/request/actor lifecycle counters. Process-wide aggregates, no per-actor labels. docs/metrics.md has the table and how to read them. The rpc crate had spawned as a dev-dependency only; it is now a dependency.

Correctness / Behavior Guarantees

  • Per-message cost without the feature is unchanged: the enqueue path and the receive loop in tasks/actor.rs differ from 0.5.0 only by the metrics hooks, plus one is_cancelled load per receive. send_after is identical. With the feature on, each message carries an inline observation and one Instant::now() per enqueue and per handler start/end (every observation is timed; timing_sample_every stays at its default of 1, since a deterministic 1-in-N sample would alias with the per-slot periodicity of lean traffic).
  • Shutdown (wait_for_shutdown: context().stop() then join()) keeps its semantics; join() is now a wrapper over wait_exit().
  • spawned's own audit of ethlambda at 78359e2c (research/backend-experiments/2026-11-06-runtime-isolation/CLIENT-WORKLOADS.md) notes the chain actor already runs on Backend::Thread, so none of 0.6.0's experimental async schedulers reach it; the metrics are the measurement that audit recommends taking first.

Tests Added / Run

  • crates/net/rpc/tests/http_servers.rs: /metrics body must contain spawned_mailbox_depth.

  • make fmt, make lint: clean on both commits

  • cargo test -p ethlambda-rpc: 361 passed, 0 failed (metrics commit)

  • The same two commits rebased onto nightly (branch bump-spawned-0.6.0-nightly): clean rebase, cargo check --locked consistent, lint clean, rpc tests 361 passed

  • make test-node: 1544 passed, 0 failed (bump commit)

  • make test-consensus: 1324 passed, 0 failed (bump commit)

  • 3-node local devnet, 0.5.0 image vs 0.6.0 image (same build flags, same roster/keys/ports, 65 slots each, run back to back with nothing else building). Same input is not possible on a live devnet, so this is a regression gate, not a perf verdict:

    Metric (3 nodes) 0.5.0 0.6.0
    head / justified / finalized slot, per node 65 / 63 / 62 65 / 63 / 62
    finalizations, blocks received 248, 130 248, 130
    tick interval mean 800.003 ms 799.996 ms
    attestation gossip arrival delay mean 37.4 ms 37.7 ms
    aggregation gossip arrival delay mean 8.1 ms 7.6 ms
    block gossip arrival delay mean 52.7 ms 27.7 ms
    fork-choice block processing mean 17.4 ms 17.7 ms
    block building mean 676 ms 584 ms
    process CPU seconds, summed 492 453
    RSS per node (process metric) 566 MiB 567 MiB
    ERROR log lines 0 0

    Consensus progress is identical and every actor-sensitive timing (tick interval, attestation/aggregation arrival, fork choice) is within noise. The two larger deltas (block arrival, block building) are live-network and XMSS-proving quantities with n=130 and n=65; not attributed to spawned.

  • 3-node local devnet on this branch's image (nightly + these two commits), 7 min / 97 slots, finalized 94, 0 ERROR lines, Prometheus + Grafana up via lean-quickstart --metrics. Per node, 2-minute rate windows at the end of the run:

    spawned_* series ethlambda_0 (aggregator) ethlambda_1 ethlambda_2
    mailbox depth (instant) 0 0 2
    queue wait p50 / p99 87 µs / 53 ms 58 µs / 30 ms 61 µs / 21 ms
    handler duration p99 785 ms 831 ms 834 ms
    messages handled / s 4.3 3.6 3.5
    enqueued = handled over the run 1722 = 1722
    rejected / discarded / panicked 0 0 0
    actors active 2 2 2

    Reading: the ~800 ms handler p99 is the block-building tick (XMSS proving); the tens-of-ms queue-wait p99 is the messages that landed behind it, and the mailbox drains to zero in between. spawned_request_latency_seconds stays empty because ethlambda's actors only cast, never call.

Note: make cooldown-check will fail until 2026-11-20 since 0.6.0 was published today.

@pablodeymo pablodeymo changed the title chore(deps): bump spawned-concurrency and spawned-rt to 0.6.0 chore(deps): bump spawned to 0.6.0 and serve its actor metrics on /metrics Nov 6, 2026
The 0.6.0 release adds actor links, monitors, exit reasons and the opt-in
framework metrics feature, and fixes the idle stop/dispatch and
shutdown-ordering races. No source changes: handler and protocol signatures
are unchanged, and the per-message enqueue and receive paths are the same
as 0.5.0 apart from metrics hooks that compile out.

ethrex-p2p (v25.0.0) keeps its own spawned 0.5.0; no spawned type crosses
that boundary, so both versions coexist in the lockfile.
spawned 0.6.0 adds an opt-in `metrics` feature with process-wide aggregates:
mailbox depth, sampled queue wait and handler duration, request latency and
lifecycle counters. Its collector is separate from the prometheus registry
and has no exporter, so `get_metrics` appends `render_prometheus()` to the
registry text. The http_servers test pins that wiring and docs/metrics.md
describes the series; `spawned_queue_wait_seconds` is the one that tells a
backed-up chain-actor mailbox apart from slow handlers.
@pablodeymo
pablodeymo changed the base branch from main to nightly November 6, 2026 17:58
The two attesters_aggregate_pubkey tests added in #742 assumed the
mainnet preset, but `make test-beacon-minimal` (and the minimal-preset
test job) runs the crate's `--lib` target with `preset-minimal` too,
so both failed on `nightly` regardless of what a PR changes:

- the_builder_key_is_the_attesters_sum_with_cold_and_warm_sums used
  slot offset 31, past minimal's 8-slot epoch (SpecAssert
  "compute_epoch_at_slot(slot) == epoch").
- a_committee_with_an_invalid_member_key_falls_back took members[5]
  of a committee that holds 4 members under minimal (index out of
  bounds).

Take the last offset from preset::SLOTS_PER_EPOCH and the bad member
from the committee's middle, so both run under either preset.

Unrelated to the spawned bump; it is here because every PR against
`nightly` hits it.

Claude-Session: https://claude.ai/code/session_011vghNnzUEcJNqbPoqE7BUE

This branch has not been deployed

No deployments
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.

2 participants