Improve high-concurrency client throughput - #1347
Merged
Merged
Conversation
Cache origins that negotiate HTTP/1.1 so automatic protocol selection does not repeat failed HTTP/2 handshakes. Avoid redundant per-chunk write deadline work, use a 64 KiB response copy buffer, and replay buffered bodies without copying their backing storage. Add regression coverage for protocol fallback, deadline refresh decisions, and independent replay cursors.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1347 +/- ##
==========================================
+ Coverage 88.45% 88.55% +0.09%
==========================================
Files 31 31
Lines 11930 11955 +25
==========================================
+ Hits 10553 10587 +34
+ Misses 1377 1368 -9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
quinnj
marked this pull request as ready for review
August 7, 2026 05:18
…buffers Review fixes for the high-concurrency throughput changes: - Guard `h1_origins` with its own lock. `_use_h2` previously took the client-global `h2_lock`, which is held across full TCP+TLS dials in `_acquire_h2_conn!`, so one slow HTTP/2 dial to any origin could stall every automatic-protocol HTTPS request on the client. The cache-hit fail-fast in `_acquire_h2_conn!` now also runs before `h2_lock`. - Clear the cache in `close_idle_connections!` so long-lived clients can re-probe origins that enable HTTP/2 later; document the cache behavior on `Client` and `close_idle_connections!`. - Make `allow_h1_alpn`/`auto_protocol` keyword arguments (the call site passed two identical adjacent positional booleans). - Right-size response copy buffers: clamp preallocated-destination copies to the destination capacity so small responses stop paying a 64 KiB scratch allocation per request, use 64 KiB for the known-large (>1 MiB hint) accumulation path and the response_stream pump, and name the 8 KiB small-loop constant with the sizing policy. - Test that a transient connect failure does not populate the h1-origin cache (only a genuine ALPN h1 negotiation may), and that close_idle_connections! clears it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Root cause
Same-region Azure Blob profiles exposed four independent costs at high concurrency.
The HTTP/1.1 origin cache applies only to
protocol = :auto. An explicitprotocol = :h2still performs HTTP/2 negotiation. Existing HTTP/2 origins keep the normal HTTP/2 path.Benchmark evidence
The benchmark used one Julia process, 64 Julia threads, Julia 1.13.0-rc1, and an Azure Standard_E64ds_v6 VM with same-region Azure Blob storage. Protocol selection remained automatic.
ProfileandProfile.Allocswere used to identify and verify the hot paths.Validation
Co-authored by Codex