-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Send trackers Stopped message when TorrentActor stops
#172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughAdds an async Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant TrackerInstance
participant UdpTracker
participant HttpTracker
participant RemoteTracker
Caller->>TrackerInstance: stop()
alt UDP variant
TrackerInstance->>UdpTracker: stop()
rect rgb(240,248,255)
note right of UdpTracker: check Ready state\nset announce_params.event = Stopped
end
UdpTracker->>RemoteTracker: announce(stop)
RemoteTracker-->>UdpTracker: response / timeout
UdpTracker-->>TrackerInstance: Ok(())
else HTTP variant
TrackerInstance->>HttpTracker: stop()
rect rgb(240,248,255)
note right of HttpTracker: set event = Stopped\nbest-effort announce with 3s timeout
end
HttpTracker->>RemoteTracker: announce(stop)
RemoteTracker-->>HttpTracker: response / timeout
HttpTracker-->>TrackerInstance: Ok(())
end
TrackerInstance-->>Caller: Ok(())
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/libtortillas/src/tracker/mod.rs (1)
169-173: Panic risk: unwrap() on UDP announce.This will panic under normal network errors; return the error instead.
Apply this diff:
async fn announce(&self) -> Result<Vec<Peer>> { match self { - TrackerInstance::Udp(tracker) => Ok(tracker.announce().await.unwrap()), + TrackerInstance::Udp(tracker) => tracker.announce().await, TrackerInstance::Http(tracker) => tracker.announce().await, } }
🧹 Nitpick comments (3)
crates/libtortillas/src/tracker/udp.rs (1)
932-951: Make UDP stop best‑effort; don’t error when not Ready and don’t fail shutdown.Currently returns Err if not Ready and propagates announce errors; actor shutdown shouldn’t fail on best‑effort stop.
Apply this diff:
#[instrument(skip(self), fields( tracker_uri = %self.uri, tracker_connection_id = ?self.get_connection_id(), torrent_id = %self.info_hash, tracker_ready_state = ?self.get_ready_state(), ))] async fn stop(&self) -> anyhow::Result<()> { - ensure!( - self.get_ready_state() == ReadyState::Ready, - "Tracker not ready for a stop request" - ); + if self.get_ready_state() != ReadyState::Ready { + trace!("Tracker not ready; skipping stop announce"); + return Ok(()); + } { self.announce_params.write().await.event = Event::Stopped; } - let _ = self.announce().await?; // Discard the response since we don't need it + if let Err(e) = self.announce().await { + debug!(error = %e, "Stop announce failed; ignoring"); + } debug!("Stopped tracker"); Ok(()) }crates/libtortillas/src/tracker/mod.rs (2)
148-150: Clarify stop() semantics as best‑effort.Consider documenting that implementors should bound I/O and avoid propagating errors during shutdown. This aligns actor teardown with resilience goals.
282-292: Don’t propagate stop() errors from on_stop; log and continue.Shutdown should be best‑effort. Propagating errors here can surface spurious failures.
Apply this diff:
async fn on_stop( &mut self, _: WeakActorRef<Self>, reason: ActorStopReason, ) -> Result<(), Self::Error> { match reason { ActorStopReason::Killed | ActorStopReason::Normal => { - self.tracker.stop().await?; - Ok(()) + if let Err(e) = self.tracker.stop().await { + debug!(error = %e, "Tracker stop on actor shutdown failed; ignoring"); + } + Ok(()) } _ => Ok(()), } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
crates/libtortillas/src/tracker/http.rs(1 hunks)crates/libtortillas/src/tracker/mod.rs(5 hunks)crates/libtortillas/src/tracker/udp.rs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
crates/libtortillas/src/tracker/http.rs (2)
crates/libtortillas/src/tracker/mod.rs (3)
uri(121-127)stop(149-149)stop(183-188)crates/libtortillas/src/tracker/udp.rs (1)
stop(938-951)
crates/libtortillas/src/tracker/mod.rs (2)
crates/libtortillas/src/tracker/http.rs (1)
stop(272-280)crates/libtortillas/src/tracker/udp.rs (1)
stop(938-951)
crates/libtortillas/src/tracker/udp.rs (2)
crates/libtortillas/src/tracker/mod.rs (3)
uri(121-127)stop(149-149)stop(183-188)crates/libtortillas/src/tracker/http.rs (1)
stop(272-280)
🔇 Additional comments (1)
crates/libtortillas/src/tracker/mod.rs (1)
183-189: Delegation looks good.TrackerInstance::stop correctly delegates to inner variants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/libtortillas/src/tracker/mod.rs(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
crates/libtortillas/src/tracker/mod.rs (2)
crates/libtortillas/src/tracker/http.rs (1)
stop(272-280)crates/libtortillas/src/tracker/udp.rs (1)
stop(938-951)
🔇 Additional comments (4)
crates/libtortillas/src/tracker/mod.rs (4)
17-18: LGTM! Necessary imports for theon_stoplifecycle hook.These imports support the new stop functionality added to the actor.
148-149: LGTM! Clean trait method addition.The
stop()method is well-documented and follows the existing trait patterns.
183-188: LGTM! Consistent delegation pattern.The implementation correctly delegates to the underlying tracker implementations and follows the same pattern as other methods in this trait impl.
287-287: Review comment is incorrect—the scenario described is not possible.The review comment assumes initialization could fail while the actor continues running, but this contradicts Kameo's behavior: if Actor::on_start returns an error, the actor will be stopped and will not continue to run/process messages.
In the code path:
TrackerActor::on_startcallsinitialize().await- If initialization fails,
on_startreturnsErr(TrackerActorError::InitializationFailed)and the actor stops- If the actor stops,
on_stopis never invoked, sotracker.stop()is never called- Conversely, when
on_stopexecutes (line 287),on_startmust have succeeded, meaninginitialize()succeeded, which guarantees the tracker was transitioned toReadyState::ReadyTherefore, the UDP tracker's
ReadyState::Readyrequirement instop()is always satisfied when called fromon_stop, and no additional error handling is needed.Likely an incorrect or invalid review comment.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
crates/libtortillas/src/tracker/http.rs (1)
267-269: Infinite recursion issue already tracked.This infinite recursion issue was previously identified and marked as out of scope for this PR. It's tracked in issue #173.
🧹 Nitpick comments (1)
crates/libtortillas/src/tracker/mod.rs (1)
282-291: LGTM! Solid best-effort shutdown implementation.The
on_stopimplementation correctly:
- Unconditionally calls
stop()for allActorStopReasonvariants (addressing previous review feedback)- Uses a 5-second timeout to prevent hanging actor shutdown
- Discards errors to ensure shutdown always proceeds
- Returns
Ok(())regardless of outcomeThe timeout duration is appropriate given the HTTP tracker's internal 3-second announce timeout.
Optional: Consider logging all stop errors for consistency.
Currently, only timeout errors are logged via
inspect_err. The HTTP tracker logs its own errors internally, but UDP tracker errors would be silently ignored. For better observability during shutdown, consider:match timeout(Duration::from_secs(5), self.tracker.stop()).await { Ok(Ok(())) => {}, Ok(Err(e)) => warn!(error = %e, "Tracker stop failed; continuing shutdown"), Err(_) => warn!("Tracker stop timed out; continuing shutdown"), }However, the current implementation is acceptable for best-effort shutdown semantics.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
crates/libtortillas/src/tracker/http.rs(2 hunks)crates/libtortillas/src/tracker/mod.rs(5 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
crates/libtortillas/src/tracker/mod.rs (2)
crates/libtortillas/src/tracker/http.rs (3)
interval(172-174)interval(267-269)stop(275-286)crates/libtortillas/src/tracker/udp.rs (3)
interval(595-597)interval(929-931)stop(938-951)
crates/libtortillas/src/tracker/http.rs (2)
crates/libtortillas/src/tracker/mod.rs (3)
uri(121-127)stop(149-149)stop(183-188)crates/libtortillas/src/tracker/udp.rs (1)
stop(938-951)
🔇 Additional comments (5)
crates/libtortillas/src/tracker/http.rs (2)
18-21: LGTM! Import additions support the new stop() functionality.The addition of
timeoutto the tokio imports is necessary for the bounded stop implementation and is correctly placed.
270-286: LGTM! Excellent best-effort stop implementation.The stop implementation correctly:
- Sets the event to
Stoppedbefore announcing- Uses a bounded 3-second timeout to prevent hanging shutdown
- Logs all outcomes appropriately (success, failure, timeout)
- Always returns
Ok(())to ensure shutdown proceeds regardless of tracker responseThis addresses the previous review feedback and follows best practices for graceful shutdown.
crates/libtortillas/src/tracker/mod.rs (3)
17-18: LGTM! Import additions support the new lifecycle hook.The new imports for
WeakActorRef,ActorStopReason,timeout, andwarnare all necessary for theon_stopimplementation and are correctly organized.Also applies to: 28-29
148-149: LGTM! Trait method addition is well-defined.The
stop()method addition to theTrackerBasetrait is correctly defined with clear documentation about its purpose: stopping the tracker and removing it from the tracker's peer list.
183-188: LGTM! Clean delegation to underlying tracker implementations.The
stop()implementation correctly delegates to both UDP and HTTP tracker variants, following the same pattern as otherTrackerBasemethods inTrackerInstance.
#108
We can't directly use
AsyncDrophere because it's not stable yet. But, we can use theon_stophook for our kameo actor for the same effect (kind of).Summary by CodeRabbit