pub struct Server { /* private fields */ }
Expand description
An HTTP server to handle incoming connections for Pavex applications. It handles both HTTP1 and HTTP2 connections.
§Example
use std::net::SocketAddr;
use pavex::server::Server;
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
Server::new()
.bind(addr)
.await?
// Both the routing function and the application state will usually
// be code-generated by Pavex, starting from your `Blueprint`.
// You don't have to define them manually!
.serve(router, application_state)
// The `serve` method returns a `ServerHandle` that you can use to
// interact with the server.
// Calling `.await` on the handle lets you wait until the server
// shuts down.
.await;
§Configuration
Server::new
returns a new Server
with default configuration.
You can customize the server default settings by creating your own ServerConfiguration
and invoking Server::set_config
.
§Architecture
By default, Server::serve
creates a worker per CPU core and distributes connection from an
acceptor thread using a round-robin strategy.
Each worker has its own single-threaded [tokio
] runtime—there is no work stealing across
workers.
Each worker takes care to invoke your routing and request handling logic, with the help
of [hyper
].
Implementations§
Source§impl Server
impl Server
Sourcepub fn set_config(self, config: ServerConfiguration) -> Self
pub fn set_config(self, config: ServerConfiguration) -> Self
Configure this Server
according to the values set in the ServerConfiguration
passed as input parameter.
It will overwrite any previous configuration set on this Server
.
If you want to retrieve the current configuration, use Server::get_config
.
Sourcepub fn get_config(&self) -> &ServerConfiguration
pub fn get_config(&self) -> &ServerConfiguration
Get a reference to the ServerConfiguration
for this Server
.
If you want to overwrite the existing configuration, use Server::set_config
.
Sourcepub async fn bind(self, addr: SocketAddr) -> Result<Self>
pub async fn bind(self, addr: SocketAddr) -> Result<Self>
Bind the server to the given address: the server will accept incoming connections from this address when started. Binding an address may fail (e.g. if the address is already in use), therefore this method may return an error.
§Related
Check out Server::listen
for an alternative binding mechanism as well as a
discussion of the pros and cons of Server::bind
vs Server::listen
.
§Note
A Server
can be bound to multiple addresses: just call this method multiple times with
all the addresses you want to bind to.
§Example: bind one address
use std::net::SocketAddr;
use pavex::server::Server;
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
Server::new()
.bind(addr)
.await?
// [...]
§Example: bind multiple addresses
use std::net::SocketAddr;
use pavex::server::Server;
let addr1 = SocketAddr::from(([127, 0, 0, 1], 8080));
let addr2 = SocketAddr::from(([127, 0, 0, 1], 4000));
Server::new()
.bind(addr1)
.await?
.bind(addr2)
.await?
// [...]
Sourcepub fn listen(self, incoming: IncomingStream) -> Self
pub fn listen(self, incoming: IncomingStream) -> Self
Ask the server to process incoming connections from the provided IncomingStream
.
§Server::listen
vs Server::bind
Server::bind
only requires you to specify the address you want to listen at. The
socket configuration is handled by the Server
, with a set of reasonable default
parameters. You have no access to the IncomingStream
that gets bound to the address
you specified.
Server::listen
, instead, expects an IncomingStream
.
You are free to configure the socket as you see please and the Server
will just
poll it for incoming connections.
It also allows you to interact with the bound IncomingStream
directly
§Example: bind to a random port
use std::net::SocketAddr;
use pavex::server::{IncomingStream, Server};
// `0` is a special port: it tells the OS to assign us
// a random **unused** port
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
let incoming = IncomingStream::bind(addr).await?;
// We can then retrieve the actual port we were assigned
// by the OS.
let addr = incoming.local_addr()?.to_owned();
Server::new()
.listen(incoming);
// [...]
§Example: set a custom socket backlog
use std::net::SocketAddr;
use socket2::Domain;
use pavex::server::{IncomingStream, Server};
// `0` is a special port: it tells the OS to assign us
// a random **unused** port
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
let socket = socket2::Socket::new(
Domain::for_address(addr),
socket2::Type::STREAM,
Some(socket2::Protocol::TCP),
)
.expect("Failed to create a socket");
socket.set_reuse_address(true)?;
socket.set_nonblocking(true)?;
socket.bind(&addr.into())?;
// The custom backlog!
socket.listen(2048_i32)?;
let listener = std::net::TcpListener::from(socket);
Server::new()
.listen(listener.try_into()?)
// [...]
§Note
A Server
can listen to multiple streams of incoming connections: just call this method
multiple times!
Sourcepub fn serve<HandlerFuture, ApplicationState>(
self,
handler: fn(_: Request<Incoming>, _: Option<ConnectionInfo>, _: ApplicationState) -> HandlerFuture,
application_state: ApplicationState,
) -> ServerHandle
pub fn serve<HandlerFuture, ApplicationState>( self, handler: fn(_: Request<Incoming>, _: Option<ConnectionInfo>, _: ApplicationState) -> HandlerFuture, application_state: ApplicationState, ) -> ServerHandle
Start listening for incoming connections.
You must specify:
- a handler function, which will be called for each incoming request;
- the application state, the set of singleton components that will be available to your handler function.
Both the handler function and the application state are usually code-generated by Pavex
starting from your Blueprint
.
§Wait for the server to shut down
serve
returns a ServerHandle
.
Calling .await
on the handle lets you wait until the server shuts down.
§Panics
This method will panic if the Server
has no registered sources of incoming connections,
i.e. if you did not call Server::bind
or Server::listen
before calling serve
.
If you’d rather handle the error, use Server::try_serve
instead.
Sourcepub fn try_serve<HandlerFuture, ApplicationState>(
self,
handler: fn(_: Request<Incoming>, _: Option<ConnectionInfo>, _: ApplicationState) -> HandlerFuture,
application_state: ApplicationState,
) -> Result<ServerHandle, Error>
pub fn try_serve<HandlerFuture, ApplicationState>( self, handler: fn(_: Request<Incoming>, _: Option<ConnectionInfo>, _: ApplicationState) -> HandlerFuture, application_state: ApplicationState, ) -> Result<ServerHandle, Error>
A fallible version of Server::serve
.
It will return an error, rather than panicking, if the Server
has no registered sources
of incoming connections, i.e. if you did not call Server::bind
or Server::listen
before calling serve
.