Repository navigation
Conversation
6e6416c to
8477d25
Compare
8477d25 to
ad88b6f
Compare
|
|
||
| /// Check both the captured generation and, for replies, the originating transport. | ||
| #[cfg(feature = "transport-streamable-http-client")] | ||
| pub(crate) fn is_current_control(&self, request: &WorkerSendRequest<W>) -> bool { |
There was a problem hiding this comment.
Is this supposed to be visible only within the crate?
| pub responder: tokio::sync::oneshot::Sender<Result<(), W::Error>>, | ||
| cancellation: Option<Arc<RequestCancellationRegistration>>, | ||
| control_generation: u64, | ||
| #[cfg(feature = "transport-streamable-http-client")] |
There was a problem hiding this comment.
Should the origin only be stored when transport-streamable-http-client is enabled?
|
Thanks for addressing my feedback, @nickcoai. I have a couple of questions before we move forward. |
| } | ||
| } | ||
|
|
||
| #[cfg(all(feature = "transport-worker", not(feature = "local")))] |
There was a problem hiding this comment.
Do we not want to run these tests with --all-features?
| // Recovery may retire the origin between the initial check and the | ||
| // worker's dispatch check. Dropping that reply must not stop a drain | ||
| // from sending later, current-session replies. | ||
| if self.is_current() { result } else { Ok(()) } |
There was a problem hiding this comment.
so the drain can tell "dropped because stale" from "the transport just broke".
| if self.is_current() { result } else { Ok(()) } | |
| match result { | |
| Err(error) if !self.is_current() => { | |
| tracing::debug!(%error, "discarding retired reply's send failure"); | |
| Ok(()) | |
| } | |
| result => result, | |
| } |
|
This has merge conflicts with |
ad88b6f to
205104e
Compare
Keep the inbound transport generation with automatic handler responses and errors. Reject replies after session recovery, including during the shutdown drain, without adding wire metadata. Match the completing handler's token before removing its request id so an old handler cannot cancel a replacement that reuses the id. Cover late replies, id reuse, scoped send context, and shutdown races.
205104e to
e575dec
Compare
| let result = send.await; | ||
| // Recovery may retire the origin between the initial check and the | ||
| // worker's dispatch check. Dropping that reply must not stop a drain | ||
| // from sending later, current-session replies. | ||
| if self.is_current() { result } else { Ok(()) } |
There was a problem hiding this comment.
Once the origin retires, this turns every send error into Ok(()), which also hides real transport failures that happen during recovery. Could the streamable HTTP worker return Ok(()) for stale replies, like the stale branch in streamable_http_client.rs already does for cancellations? Then we could remove this re-check and its comment.
| let result = send.await; | |
| // Recovery may retire the origin between the initial check and the | |
| // worker's dispatch check. Dropping that reply must not stop a drain | |
| // from sending later, current-session replies. | |
| if self.is_current() { result } else { Ok(()) } | |
| send.await |
| #[tokio::test] | ||
| async fn shutdown_drain_preserves_current_handler_after_old_response_or_error() { | ||
| for error in [false, true] { | ||
| for replacement_id in [8, 7] { |
There was a problem hiding this comment.
The nested loops put four scenarios in one test, with a 5-second timeout for each step. If one case hangs, it hides the others. Could we use rstest values to make each combination its own test?
| #[tokio::test] | |
| async fn shutdown_drain_preserves_current_handler_after_old_response_or_error() { | |
| for error in [false, true] { | |
| for replacement_id in [8, 7] { | |
| #[rstest::rstest] | |
| #[tokio::test] | |
| async fn shutdown_drain_preserves_current_handler_after_old_response_or_error( | |
| #[values(false, true)] error: bool, | |
| #[values(8, 7)] replacement_id: i64, | |
| ) { | |
| { | |
| { |
| #[test] | ||
| fn old_handler_completion_preserves_reused_id_owner() { | ||
| for error in [false, true] { |
There was a problem hiding this comment.
We could use rstest here as well.
Summary
Fix the late-handler reply issue from Dale's review.
This PR is based on
main, independently of the worker refactor in #1205. The late-handler routing issue predates #1186. Whichever follow-up lands second will need a rebase to combine their transport changes.Scope
This protects automatic service replies, including request-association errors. Manually constructed raw transport replies have no captured origin.
Transport wrappers must preserve request extensions. Wrappers that defer the inner send within the same future retain the reply context; detached tasks must construct the inner send before spawning. Serializing requests or deferring send construction to a detached task loses the private context.
The tests cover late success and error replies, reused request ids, shutdown draining, and recovery during a pending reply send.
Validation
Rebased on
mainat50fba5c2848d3ef9d0df0efacb8a7d001914f40e(October 17).Exact head
e575decaa047d9531fd918bb7afc61d074a0c9fais green in CI, including all-features tests, non-local tests, clippy, MSRV, public API/semver checks, coverage, and examples. CodeQL also passed.Local checks passed: 283 library tests with
client,transport-streamable-http-client, all 24 streamable-http concurrency tests, nightly formatting, andgit diff --check.