Skip to content

Conversation

rylev
Copy link
Collaborator

@rylev rylev commented Oct 2, 2025

Fixes #3281

Wraps outbound requests in a semaphore with configurable permit size. This allows runtime config to decide how many outbound requests may be made at a give time.

@rylev rylev requested review from lann and dicej October 2, 2025 10:19
@lann
Copy link
Collaborator

lann commented Oct 2, 2025

It just occured to me how we could limit actual connections instead of requests:

struct PermittedTcpStream {
  inner: TcpStream,
  permit: OwnedSemaphorePermit,
}

// simple wrappers just like our existing `RustlsStream`
impl AsyncRead for PermittedTcpStream { ... }
impl AsyncWrite for PermittedTcpStream { ... }

The permit would be acquired out in RequestSender::send_request and passed in to ConnectOptions and used to construct the PermittedTcpStream in HttpConnector. The permit would automatically be dropped when the stream is dropped.

@rylev rylev force-pushed the max-number-requests branch from f20022c to d9fab0e Compare October 6, 2025 12:35
@rylev rylev requested a review from dicej October 6, 2025 12:40
@rylev rylev force-pushed the max-number-requests branch from d9fab0e to 68e5471 Compare October 6, 2025 12:43
Copy link
Contributor

@dicej dicej left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

Comment on lines +63 to +65
// Permit count is the max concurrent connections + 1.
// i.e., 0 concurrent connections means 1 total connection.
.map(|n| Arc::new(Semaphore::new(n + 1))),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not a huge deal since we're talking about rather large limits but I don't understand this interpretation. I would expect "0 concurrent connections" to mean "you can't ever connect" (which should perhaps be invalid).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess I have a different interpretation. A concurrent request is by definition one that is happening during another request. 0 concurrent requests would therefore mean "no requests happening at the same time" not "no requests at all". I think we should just pick which ever interpretation is most convenient and use that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

How many requests are involved in "2 concurrent requests"?

Copy link
Collaborator

Choose a reason for hiding this comment

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

A concurrent request is by definition one that is happening during another request

That is strictly true, but I think that doing the +1 makes everything else more confusing. The first request becomes concurrent once there is two total requests.

I'd vote for removing the + 1

Comment on lines 460 to 464
// If we're limiting concurrent outbound requests, acquire a permit
let permit = match self.concurrent_outbound_connections_semaphore {
Some(s) => s.acquire_owned().await.ok().map(Arc::new),
None => None,
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this needs to be moved down into ConnectOptions::connect_tcp or it will still be limiting requests instead of connections.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah yea of course!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should be good now: a472018

@rylev rylev requested a review from lann October 7, 2025 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Limit the number of concurrent outbound HTTP requests
4 participants