fix: remove duplicate receive loops in P2PNode#10
fix: remove duplicate receive loops in P2PNode#10dirvine merged 1 commit intofix/p2p-event-source-peer-idfrom
Conversation
…ew() to start() P2PNode::new() and start() both called start_network_listeners() and start_message_receiving_system(), spawning duplicate accept and receive loops competing on the same QUIC endpoint. This caused messages to be randomly split between loops, leading to flaky delivery. Now new() only constructs the struct; start() is the single place where background loops are spawned. All callers updated to call start() after new(). Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
@claude review please |
|
Claude finished @dirvine's task in 1m 48s —— View job Code Review Complete ✅SummaryThis PR successfully eliminates duplicate receive loops by cleanly separating node construction from network initialization. The fix is correct and well-implemented. All call sites have been properly updated, and the changes follow repository standards. Review Findings✅ Strengths
🔍 Observations (Not Issues)
|
Code Review: PR #10 - fix: remove duplicate receive loops in P2PNodeHey @mickvandijke, nice clean fix! Here's my review. 📝 SummaryThis PR addresses a race condition where
The fix: Constructor ( ✅ What Looks Good
|
|
Missing guard in start() method - The start() method can be called multiple times and spawn duplicate tasks. Add a guard: if *self.running.read().await { return Ok(()); } at the beginning of start() to prevent duplicate task spawning. See src/network.rs:1122-1166 |
|
Detailed review: The start() method at src/network.rs lines 1122-1166 needs a guard to prevent duplicate task spawning. Current code spawns tasks unconditionally. Suggested fix: Add check at start of method - if running.read().await is true, return Ok early. This prevents the exact race condition the PR fixes. Reference the run() method which already has this guard pattern. |
…ing) Implements 11 hardening improvements from PR #21 review comments: 1. Request Leak/Cleanup: - Added RAII RequestCleanupGuard for automatic cleanup on drop/cancel - Atomic check+insert under single write lock to prevent races 2. Input Validation: - Added TransportError::ValidationError for input validation errors - validate_protocol_name() now uses ValidationError instead of StreamError 3. Timeout Handling: - Added MIN_REQUEST_TIMEOUT (100ms) to prevent Duration::ZERO immediate timeout - send_request() clamps timeout to [100ms, 5min] range 4. Response Routing: - Improved logging for failed pending.send() to clarify timeout scenario 5. Documentation: - Added documentation to ReplicationResult clarifying remote-only counts - Fixed brittle error assertion in tests to check error variant 6. Testing: - New tests/request_response_e2e_test.rs with 7 comprehensive tests: * Successful request/response routing * Timeout cleanup behavior * Invalid protocol rejection (empty, /, \, \0) * Protocol validation in send_response() * Minimum timeout enforcement * Trust reporting on failure Items already correct (verified): - #3: Protocol validation in send_response() already present - #6: Response-origin mismatch uses get() before remove() - #7: Unmatched /rr/ responses already suppressed - #9: Trust reporting on send_message() failure already implemented - #10: PeerStoreOutcome docs correct (no latency mention) Closes #23 Co-authored-by: David Irvine <[email protected]>
Summary
P2PNode::new()— the constructor now only builds the struct without spawning any tasksstart()is now the single entry point for spawning accept loops, receive loops, and the connection monitorstart()afternew()Context
P2PNode::new()andstart()both calledstart_network_listeners()andstart_message_receiving_system(), spawning duplicate accept and receive loops competing on the same QUIC endpoint. Two receive loops callingreceive_any()race on every incoming message — only one wins, so each loop sees roughly half the traffic, causing flaky message delivery.Dependencies
Test plan
cargo build— compiles cleanlycargo clippy -- -D warnings -D clippy::unwrap_used -D clippy::expect_used— zero warningscargo test --lib— all 1332 unit tests pass🤖 Generated with Claude Code