Reduce session-affinity async allocations - #3042
Closed
artl93 wants to merge 2 commits into
Closed
Conversation
added 2 commits
July 12, 2026 13:56
Use completion-aware fast paths for synchronous affinity and failure policies while preserving asynchronous provider behavior and exception semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72d2ca2f-41bd-4159-aafd-717a139efea2
Cover cancellation that occurs after a custom affinity provider suspends, ensuring the middleware returns a canceled task. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72d2ca2f-41bd-4159-aafd-717a139efea2
MihaZupan
reviewed
Jul 20, 2026
MihaZupan
left a comment
Member
There was a problem hiding this comment.
I do not believe adding duplication/complexity like this is worth it, especially as runtime async is changing tradeoffs, potentially making it a deoptimization to manually split methods and check task.IsCompleted.
Member
Author
|
Thanks, @MihaZupan - closing out. |
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.
Summary
SessionAffinityMiddlewarecurrently keeps its own async state machine alive while awaiting the downstream proxy pipeline. Built-in affinity policies usually complete synchronously, while forwarding normally suspends.This change handles synchronously completed affinity results inline and returns the downstream task directly. It avoids one middleware async-frame allocation without changing the public policy interfaces.
Scope: this only benefits affinity-enabled requests where the affinity/failure policy completes synchronously and downstream completes asynchronously. Affinity-disabled requests, immediate failures that do not call downstream, and genuinely asynchronous custom policies do not receive the same reduction.
This PR remains draft.
BenchmarkDotNet results
EgorBot does not appear to be enabled for
dotnet/yarp: there is no repository workflow, configuration, or prior invocation in YARP history. As a cross-platform substitute, I ran BenchmarkDotNet 0.15.8 locally with separate exact-parent and exact-final jobs:49b23da6d8b0e9df47abf45d7755173f8467094169457515f0f0a9e5b99d83d9384360b1889a0366d3627b95676a7f28c812616e4bb7ca652e2916a6(test-only follow-up; product source is unchanged)11.0.100-preview.5.26227.104, runtime .NET 9.0.2MemoryDiagnoserComponent pipeline
The allocation reduction is limited to the synchronous-policy/async-downstream path. Synchronous downstream and disabled controls are unchanged. Genuinely asynchronous custom-policy controls show a small +8 B/request tradeoff.
Real Kestrel proxy path
The BDN method sends a real loopback request through Kestrel,
MapReverseProxy, and a Kestrel backend.Async header-policy controls varied from -14 to +40 B/request in the Kestrel run, consistent with no material allocation improvement for that path.
Timing was noisy and BDN's 5% equivalence test reported the main cookie and Kestrel comparisons as
Same. No throughput or latency improvement is claimed. The supported result is the allocation reduction above.Allocation trace
Exact-binary EventPipe traces sampled the parent
SessionAffinityMiddleware.<InvokeInternal>state-machine box 1,747 times on misses and 2,467 times on hits. Final hit/miss traces sampled it zero times. Disabled traces sampled it zero times on both sides.Correctness
Synchronous exceptions are converted back into returned tasks using
ExceptionDispatchInfo, preserving the original async method behavior. Canceled operations remain canceled tasks. Faulted/canceledValueTasks still take the await path, and eachValueTaskis consumed once.Tests cover:
Validation:
d3627b95676a7f28c812616e4bb7ca652e2916a6/ merge34b835fa480590f04c2d9dbc6eacc533a7cc5093: Windows (NetCore-Public 529), Ubuntu (Azure Pipelines 146), and macOS latest (Azure Pipelines 56); Docker, lint, and CLA checks also passedEvidence and limitations
The standalone benchmark is a session artifact rather than a product-tree benchmark. It references the exact parent/final YARP DLLs and can run on any platform supported by BDN and YARP.
3549b8ad0eb4f28d5355683c145ec3a7c9e0d63f63b277d2b8f8fd95261a95901a7477d2de7f6d214ead3a45be68ed36cb00fbc189716bac6610a0daea4caaa6ae1c361dde8e58afb9535410beb56c7aff7ea497639234458da1c2b874b7b215358cea3e7df9225f2967f244dcc075eab82351dcd805d549f217f1b87b055103Cookie parsing and
HttpContext.Itemsallocations are unchanged. This PR removes only the additional session-affinity middleware async frame.