Repository navigation
fix(node): keep protocol routing running when its event receiver lags - #285
mickvandijke wants to merge 1 commit into
Conversation
Protocol routing read the P2P event stream with `while let Ok(event) = events.recv().await`. saorsa-core's event channel holds 1000 events, shared by every inbound message and peer event. If routing fell further behind than that, `recv()` returned `RecvError::Lagged` and the loop ended. The node stayed in its peers' routing tables but answered no chunk request until restart, and nothing was logged. `ProtocolEvents` now wraps the receiver for routing. On a lag it counts the skipped events (`routing_lagged_event_count` in the chunk RPC traffic summary) and carries on from the oldest event the channel kept. It warns at most once every 10 s, naming the node, because under sustained overload the receiver lags again almost at once. Only a closed stream ends routing, as ADR-0005 decision 4 already does for replication. The devnet and e2e harness routing loops had the same pattern and use the same type. Closes V2-1448 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaidSafe-Hermes
left a comment
There was a problem hiding this comment.
APPROVE — reviewed commit 8a61dcd5cbaf155bd4dab556c8dce5c441a77e81.
Both seats agree (two model families): 2/2 seats reviewed (sol-1 gpt-6.1-sol xhigh; glm-1 z-ai/glm-5.3).
ProtocolEvents::recv recovers from RecvError::Lagged, counts every skipped event, throttles per-reader warnings, and exits only when the stream closes. The live node, devnet and e2e routing loops all use it. The new tests cover overflow recovery, continued post-lag chunk PUT handling, warning suppression, retained events and closure. I found no blocking defect.
All current PR checks pass, including Linux, macOS and Windows tests, Rust 1.95 MSRV, storage, security audit and CI Gate. The test suite does not directly assert the exported lag metric; this is a non-blocking coverage gap.
Linear issue
Closes V2-1448
Protocol routing no longer stops for good when it falls behind the P2P event stream. This is Darwin disclosure issue #4.
The bug
RunningNode::start_protocol_routingread events withwhile let Ok(event) = events.recv().await(src/node.rs).eventsis a tokio broadcast receiver fromP2PNode::subscribe_events(). saorsa-core 0.30.0 fixes its capacity atDEFAULT_EVENT_CHANNEL_CAPACITY = 1000(lib.rs:139, passed in atnetwork.rs:1105). Every inbound app message on every topic goes through it, along with every peer connect and disconnect.recv()returnsRecvError::Lagged(n)and thewhile letends. The node stays in its peers' routing tables and keeps replicating, which uses a separate receiver. But it answers no chunk GET, PUT or quote until restart, and nothing is logged.src/devnet.rs) and e2e harness (tests/e2e/testnet.rs) routing loops.What changes
ProtocolEvents(ant_node::node::ProtocolEvents) wraps the receiver for all three loops. A lag is passed over and reading resumes at the oldest event the channel kept. OnlyRecvError::Closedends routing. This is the rule ADR-0005 decision 4 already applies to replication.routing_lagged_event_count, a new field on thegroup = 1line of the periodic chunk RPC traffic summary. It covers all topics, since a skipped event can't be read.tokio-1.53.3/src/sync/broadcast.rs,recv_ref). A warning per lag would log at close to the event rate. So the warning fires at most once every 10 s and carries the total missed since the last one. It names the node: its peer ID on a real node,node Nin the devnet and e2e harness.Not in this PR
handle_replication_event_recv_error(src/replication/mod.rs) warns on every lag too, so it has the same log-flood behaviour. It could reuse the throttle in a follow-up.src/replication/bootstrap.rsends its 60 s wait forBootstrapCompleteearly on a lag. It logs a warning and continues, and neighbour sync catches up later, so it's low severity.Risk tier
Proposed T2: node behaviour changes, but only after a lag, where routing now keeps running instead of stopping. The healthy path, the wire format and storage are unchanged.
Compatibility
ant_node::node::ProtocolEvents(new,recv). Nothing existing changes. The chunk RPC traffic summary'sgroup = 1line gains arouting_lagged_event_countfield.Semver impact
featurebecause of the new public type. Behaviourally this is a fix.Test evidence
Local, macOS, rustc 1.96.1, at 8a61dcd:
node::tests::protocol_routing_survives_a_lagged_event_receiverruns against a real node:publishdoesn't suspend, so routing can't run during the flood.Lagged, which proves the channel overflowed.node::tests::protocol_events_pass_over_lags_and_end_on_close:recvreturning onLagged, the old behaviour, the regression test fails with "protocol routing stopped after its event receiver lagged".cargo test --lib -- node::tests storage::trafficpasses 28 tests, and 27 with--no-default-features.cargo check --all-targets --all-features, which includes the e2e target, is clean.cargo check --lib --no-default-featuresandRUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-depsare clean.cargo fmt --all -- --checkis clean.cargo clippy --all-targets --all-features -- -D warningsfinds nothing in the changed files. Local 1.96 flags 6 findings in untouched files (replication/pointer.rs,storage/chunk_store.rs,devnet/run_dir.rs), the same as on unchanged origin/main.New dependency
none
ADR
ADR-0005, decision 4: "Treat closed event streams as terminal; keep lag recoverable". This PR applies that existing rule to protocol routing; no new decision.
Mitigation / rollback
Revert. The only behaviour change is that routing keeps running after a lag where it used to stop.
🤖 Generated with Claude Code