Hello,
I'm working on an API gateway in Axum, which should detect requests on multiple routes and call the correct service based on the route. For example:
- request on
localhost:2000/users/<path>
is translated to a request tolocalhost:3000/users/<path>
- request on
localhost:2000/profiles/<path>
is translated to a request tolocalhost:4000/profiles/<path>
To do this I took the Axum example of a reverse proxy (Axum reverse proxy example) and modified it like that:
#[tokio::main]
async fn main() {
// Hyper client for making requests
let client = hyper::Client::new();
// Axum router
let router: Router<Body> = Router::new()
.route("/users/*path" , any(request_handler))
.route("/profiles/*path", any(request_handler))
.layer(Extension(client));
// Start server
Server::bind(&"0.0.0.0:2000".parse().unwrap())
.serve(router.into_make_service())
.await
.unwrap();
}
async fn request_handler(
Extension(client): Extension<hyper::Client<HttpConnector>>,
mut req: Request<Body>,
) -> impl IntoResponse {
// Extract path
let path = req.uri().path();
let path_query = req
.uri()
.path_and_query()
.map(|v| v.as_str())
.unwrap_or(path);
// Get first part of the path
let path_parts: Vec<&str> = path.split("/").collect();
let path_base = path_parts.get(1).expect("no base path");
// Map first part of path to host
let host: String;
match *path_base {
"users" => host = "http://0.0.0.0:3000".into(),
"profiles" => host = "http://0.0.0.0:4000".into(),
&_ => todo!()
}
// Construct URI
let uri = format!("{}{}", host, path_query);
// Prepare request and return
*req.uri_mut() = Uri::try_from(uri).unwrap();
client.request(req).await.unwrap()
}
According to the documentation of hyper::Client
cloning an instance of a client is the recommended way to share a hyper::Client
. And as far as I understand the use of axum::extension::Extension
as a layer clones the hyper::Client
. So far so good.
What I'm curious about now is the following:
- Is the shared
hyper::Client
a problem regarding performance and concurrency? - Which connection pool does my instance of
hyper::Client
use? Does it share the connection pool with Axum? If so, how does my instance ofhyper::Client
know which pool to use or that there is an existing pool?
And some general questions that came up during research:
- Where does Axum create an instance/multiple instances of
hyper::Client
? I looked through the source code but couldn't find it. - Does Axum or Hyper take care of spawning Tokio tasks? Is every request handled in a seperate
tokio::task
?
Thanks to everyone who made it through all of my text
Any help is very much appreciated. Thanks in advance.