Skip to content

Conversation

@seanmonstar
Copy link
Member

Just a combined pull request for generating docs previews and some CI testing, look at the separate PRs for the individual pieces.

@seanmonstar

This comment was marked as outdated.

2 similar comments
@seanmonstar

This comment was marked as outdated.

@seanmonstar

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@seanmonstar

This comment was marked as outdated.

@seanmonstar

This comment was marked as outdated.

@seanmonstar
Copy link
Member Author

/rustdoc-preview

@github-actions
Copy link

📝 Rustdoc preview for this PR: View docs

@seanmonstar seanmonstar force-pushed the pool-ng branch 2 times, most recently from 778d49d to 7b668a6 Compare September 19, 2025 20:38
@seanmonstar
Copy link
Member Author

/rustdoc-preview

@github-actions
Copy link

📝 Rustdoc preview for this PR: View docs

Copy link

@sjcobb2022 sjcobb2022 left a comment

Choose a reason for hiding this comment

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

Looking great overall. Will test in some crates later on in the week

use http_body_util::Empty;
use hyper::Request;
use hyper_util::client::legacy::{connect::HttpConnector, Client};
use hyper_util::client::pool;

Choose a reason for hiding this comment

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

nit: rename file to client_pool


let mut p = pool::Cache::new(http1).build();

let mut c = p.call(http::Uri::from_static("http://hyper.rs")).await?;

Choose a reason for hiding this comment

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

nit: use consistent uri for all calls.

let req = Request::builder()
.uri(url)
.body(Empty::<bytes::Bytes>::new())?;
async fn send_nego() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {

Choose a reason for hiding this comment

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

nit: send_negotiate


for _ in 0..5 {
let mut c = svc
.call(http::Uri::from_static("http://localhost:3000"))

Choose a reason for hiding this comment

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

change to hyper.rs (or keep consistent with all other tests)

Comment on lines +3 to +9
//! The map isn't a typical `Service`, but rather stand-alone type that can map
//! requests to a key and service factory. This is because the service is more
//! of a router, and cannot determine which inner service to check for
//! backpressure since it's not know until the request is made.
//!
//! The map implementation allows customization of extracting a key, and how to
//! construct a MakeService for that key.

Choose a reason for hiding this comment

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

Potential rewrite:

This map is not a traditional Service; instead, it is a standalone type that allows users to associate incoming keys with service factories. For each request, a key is extracted and used to select or construct a corresponding service.

Because this service acts more like a router, it cannot determine which inner service to check for backpressure ahead of time; the appropriate service is only known once a request has been received.

let mut pool = super::Map::builder().keys(|_| "a").values(|_| "b").build();
pool.service(&"hello");
}
}

Choose a reason for hiding this comment

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

    #[test]
    fn it_returns_same_service_for_same_key() {
        let mut pool = Map::builder()
            .keys(|s: &&str| *s)
            .values(|_| {
                String::from("service")
            })
            .build();

        let service1 = pool.service(&"foo") as *const String;
        let service2 = pool.service(&"foo") as *const String;

        // Should be the same pointer.
        assert_eq!(service1, service2);
    }

    #[test]
    fn it_returns_different_service_for_different_keys() {
        let mut pool = Map::builder()
            .keys(|s: &&str| *s)
            .values(|s| format!("service-for-{}", s))
            .build();

        let service1 = pool.service(&"foo") as *const String;
        let service2 = pool.service(&"bar") as *const String;

        // Should NOT be the same pointer (different key/service)
        assert_ne!(service1, service2);

        // Optionally, check the actual value
        assert_eq!(pool.service(&"foo"), "service-for-foo");
        assert_eq!(pool.service(&"bar"), "service-for-bar");
    }

Comment on lines +3 to +8
//! The singleton pool combines a MakeService that should only produce a single
//! active connection. It can bundle all concurrent calls to it, so that only
//! one connection is made. All calls to the singleton will return a clone of
//! the inner service once established.
//!
//! This fits the HTTP/2 case well.

Choose a reason for hiding this comment

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

Take it or leave it:

The singleton pool manages a MakeService that should only produce a single active connection.

T::Key: Eq + std::hash::Hash,
{
/// Get a service after extracting the key from `req`.
pub fn service(&mut self, req: &Req) -> &mut T::Service {

Choose a reason for hiding this comment

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

Would it still be worth implementing Service for this, which just calls the underlying method? Means we have a "consistent" API for all the pool methods.

Copy link
Member Author

Choose a reason for hiding this comment

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

So far I still think it's proper to not provide the impl. Wouldn't be a problem to eventually add one if so needed.

Choose a reason for hiding this comment

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

Yeh sounds good.

Copy link

@sjcobb2022 sjcobb2022 Nov 4, 2025

Choose a reason for hiding this comment

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

Actually, if we want to store Map, it would be much nicer if we had Service for it, since that means we can name the type that we can name the type of the returned service.

e.g. we can store cache, singleton, and negotiate because they can be abstracted away into Services over children services, but since target is private we can't really name it.

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.

3 participants