tonic/client: support immediate cancellation of streams without sending End-of-Stream - #2791
Draft
arjan-bal wants to merge 7 commits into
Draft
tonic/client: support immediate cancellation of streams without sending End-of-Stream#2791arjan-bal wants to merge 7 commits into
arjan-bal wants to merge 7 commits into
Conversation
arjan-bal
marked this pull request as draft
August 4, 2026 21:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Tonic's client streaming and bidirectional (bidi) streaming APIs do not currently support immediate request cancellation. Because outbound request streams are infallible, completing or dropping a stream automatically transmits a
DATAframe with anEnd-of-Stream (EOS)flag, which signals a normal, graceful termination. AnRST_STREAMframe is only sent by the client after the request stream terminates and the corresponding response stream is subsequently dropped.This delayed teardown creates a problem: the server may interpret the
EOSflag as a graceful finish and process or commit incomplete payloads before it ever receives theRST_STREAMframe. To prevent potential data corruption, Tonic requires a mechanism to abort and tear down the HTTP/2 stream immediately without sending a misleadingEOSflag.Solution
Introduce a paired
CancellationHandleandCancellationListenermechanism to coordinate immediate, client-side cancellation of outbound request streams.Core Changes
CancellationHandle(User-Facing): Users can create a handle and insert it into the gRPC requestExtensionscontainer. Invoking.cancel()on this handle triggers an immediate, non-graceful abort.CancellationListener(Internal): Extracted from the request extensions by Tonic's client dispatcher to actively track the cancellation state of the active stream.CancellationStateutilizingAtomicBoolandAtomicWaker. This allows lock-free, wake-ups and state checks across task boundaries without relying on mutexes.EncodeBody::poll_frameactively checks theCancellationListener. If cancellation is flagged, it immediately returns an error mapped withH2Reason::CANCEL. This bypasses the emptyDATAframe withEOSand immediately triggers an HTTP/2 levelRST_STREAM.Alternative
Use the Encoder API to inject an error causing hyper to cancel the stream: #2788
This seems like a mis-use of the codec API and causes the RST_STREAM code to be
internal.