Skip to content

Remember the last received HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS for a given host - #128954

Merged
MihaZupan merged 7 commits into
mainfrom
copilot/memorizestream-limit-connection
Jun 4, 2026
Merged

MihaZupan merged 7 commits into
mainfrom
copilot/memorizestream-limit-connection

Conversation

Copilot AI commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

The same way we remember the last received SETTINGS_MAX_HEADER_LIST_SIZE for HTTP/2 and 3, we can remember the last server-advertised stream limit.

// These settings are advertised by the server via SETTINGS_MAX_HEADER_LIST_SIZE and SETTINGS_MAX_FIELD_SECTION_SIZE.
// If we had previous connections to the same host in this pool, memorize the last value seen.
// This value is used as an initial value for new connections before they have a chance to observe the SETTINGS frame.
// Doing so avoids immediately exceeding the server limit on the first request, potentially causing the connection to be torn down.
// 0 means there were no previous connections, or they hadn't advertised this limit.
// There is no need to lock when updating these values - we're only interested in saving _a_ value, not necessarily the min/max/last.
internal uint _lastSeenHttp2MaxHeaderListSize;
internal uint _lastSeenHttp3MaxHeaderListSize;

Imagine a scenario where the server advertises a 10-stream limit per connection, and we attempt to send a burst of 100 requests.

  • As soon as we establish a connection, we'll try to send all 100 requests over that one connection since that is our initial concurrency assumption.
  • The server will ACK with a stream limit of 10, and we'll abort the 90 requests that are over the limit, and automatically retry them
  • The next connection we establish, we'll again try to send all 90 pending requests, then abort 80 of those ...

Since we limit the number of retries we'll attempt, lots of those requests will end up failing with an error.

After this change though, everything after the first connection attempt will remember that the observed limit was in fact 10, so starting with the 2nd connection we won't try to send more than the 10 streams at a time, avoiding the need to retry anything, and those requests will eventually succeed on new connections.
Without #66944 that might still take a while (opening 10 connections one at a time), but at least the requests won't prematurely fail. Remembering the last value we received is also good to inform whatever heuristic we might end up using for #66944 in the future.

Copilot AI self-assigned this Jun 3, 2026
Copilot AI review requested due to automatic review settings June 3, 2026 17:02
Copilot AI removed the request for review from Copilot June 3, 2026 17:02
@MihaZupan MihaZupan changed the title Clean up Http2_ServerAdvertisesLowMaxConcurrentStreams_PoolMemorizesValueAcrossConnections test Remember the last received HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS for a given host Jun 3, 2026
@MihaZupan MihaZupan added this to the 11.0.0 milestone Jun 3, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@MihaZupan

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@MihaZupan
MihaZupan marked this pull request as ready for review June 3, 2026 17:16
Copilot AI review requested due to automatic review settings June 3, 2026 17:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates SocketsHttpHandler’s HTTP/2 connection startup behavior to seed a new connection’s initial SETTINGS_MAX_CONCURRENT_STREAMS assumption from the last value observed for the same HttpConnectionPool (host), similar to existing memoization for SETTINGS_MAX_HEADER_LIST_SIZE. This helps avoid over-scheduling streams on freshly created connections when the server enforces a low concurrent-stream limit, reducing refused streams and subsequent retries.

Changes:

  • Add per-pool memoization for the last seen HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS.
  • Initialize new Http2Connection instances’ _maxConcurrentStreams from the pool’s last seen value and update the cached value when processing SETTINGS.
  • Add a functional test covering the “low max concurrent streams across multiple connections” scenario.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs Adds a functional test intended to validate that the pool remembers low MAX_CONCURRENT_STREAMS across connections.
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs Seeds initial per-connection max concurrent streams from the pool and records server-advertised values when SETTINGS are processed.
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs Introduces _lastSeenHttp2MaxConcurrentStreams cached per pool (host) with an initial default.

Comment thread src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs Outdated
Copilot AI review requested due to automatic review settings June 3, 2026 19:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

@MihaZupan

Copy link
Copy Markdown
Member

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@MihaZupan
MihaZupan merged commit 2364d61 into main Jun 4, 2026
94 of 104 checks passed
@MihaZupan
MihaZupan deleted the copilot/memorizestream-limit-connection branch June 4, 2026 10:19
@dotnet-milestone-bot dotnet-milestone-bot Bot modified the milestones: 11.0.0, 11.0-preview6 Jun 5, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants