From 17fd135349967597fc35e066d0d32078259fd0d4 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 29 Oct 2023 18:37:29 +0000 Subject: [PATCH] docs: improve docs on ServerBuilder::{bind, workers} --- actix-server/src/builder.rs | 78 +++++++++++++++++++++++++++++-------- justfile | 9 +++++ 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index 42addafc..33da31c5 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -2,7 +2,6 @@ use std::{io, num::NonZeroUsize, time::Duration}; use actix_rt::net::TcpStream; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; -use tracing::{info, trace}; use crate::{ server::ServerCommand, @@ -69,19 +68,18 @@ impl ServerBuilder { } } - /// Set number of workers to start. + /// Sets number of workers to start. /// /// `num` must be greater than 0. /// - /// The default worker count is the number of physical CPU cores available. If your benchmark - /// testing indicates that simultaneous multi-threading is beneficial to your app, you can use - /// the [`num_cpus`] crate to acquire the _logical_ core count instead. + /// Note that the factory + /// + /// The default worker count is the determined by [`std::thread::available_parallelism()`]. See + /// its documentation to determine what behavior you should expect when server is run. /// /// # Panics /// /// Panics if `num` is 0. - /// - /// [`num_cpus`]: https://docs.rs/num_cpus pub fn workers(mut self, num: usize) -> Self { assert_ne!(num, 0, "workers must be greater than 0"); self.threads = num; @@ -155,13 +153,15 @@ impl ServerBuilder { self.max_concurrent_connections(num) } - /// Stop Actix `System` after server shutdown. + /// Sets flag to stop Actix `System` after server shutdown. + /// + /// This has no effect when server is running in a Tokio-only runtime. pub fn system_exit(mut self) -> Self { self.exit = true; self } - /// Disable OS signal handling. + /// Disables OS signal handling. pub fn disable_signals(mut self) -> Self { self.listen_os_signals = false; self @@ -179,25 +179,49 @@ impl ServerBuilder { self } - /// Add new service to the server. - pub fn bind(mut self, name: N, addr: U, factory: F) -> io::Result + /// Adds new service to the server. + /// + /// Note that, if a DNS lookup is required, resolving hostnames is a blocking operation. + /// + /// # Worker Count + /// + /// The `factory` will be instantiated multiple times in most scenarios. The number of + /// instantiations is number of [`workers`](Self::workers()) × number of sockets resolved by + /// `addrs`. + /// + /// For example, if you've manually set [`workers`](Self::workers()) to 2, and use `127.0.0.1` + /// as the bind `addrs`, then `factory` will be instantiated twice. However, using `localhost` + /// as the bind `addrs` can often resolve to both `127.0.0.1` (IPv4) _and_ `::1` (IPv6), causing + /// the `factory` to be instantiated 4 times (2 workers × 2 bind addresses). + /// + /// Using a bind address of `0.0.0.0`, which signals to use all interfaces, may also multiple + /// the number of instantiations in a similar way. + /// + /// # Errors + /// + /// Returns an `io::Error` if: + /// - `addrs` cannot be resolved into one or more socket addresses; + /// - all the resolved socket addresses are already bound. + pub fn bind(mut self, name: N, addrs: U, factory: F) -> io::Result where F: ServerServiceFactory, U: ToSocketAddrs, N: AsRef, { - let sockets = bind_addr(addr, self.backlog, &self.mptcp)?; + let sockets = bind_addr(addrs, self.backlog, &self.mptcp)?; - trace!("binding server to: {:?}", &sockets); + tracing::trace!("binding server to: {sockets:?}"); for lst in sockets { let token = self.next_token(); + self.factories.push(StreamNewService::create( name.as_ref().to_string(), token, factory.clone(), lst.local_addr()?, )); + self.sockets .push((token, name.as_ref().to_string(), MioListener::Tcp(lst))); } @@ -205,7 +229,12 @@ impl ServerBuilder { Ok(self) } - /// Add new service to the server. + /// Adds service to the server using a socket listener already bound. + /// + /// # Worker Count + /// + /// The `factory` will be instantiated multiple times in most scenarios. The number of + /// instantiations is: number of [`workers`](Self::workers()). pub fn listen>( mut self, name: N, @@ -237,7 +266,7 @@ impl ServerBuilder { if self.sockets.is_empty() { panic!("Server should have at least one bound socket"); } else { - info!("starting {} workers", self.threads); + tracing::info!("starting {} workers", self.threads); Server::new(self) } } @@ -251,7 +280,12 @@ impl ServerBuilder { #[cfg(unix)] impl ServerBuilder { - /// Add new unix domain service to the server. + /// Adds new service to the server using a UDS (unix domain socket) address. + /// + /// # Worker Count + /// + /// The `factory` will be instantiated multiple times in most scenarios. The number of + /// instantiations is: number of [`workers`](Self::workers()). pub fn bind_uds(self, name: N, addr: U, factory: F) -> io::Result where F: ServerServiceFactory, @@ -271,9 +305,14 @@ impl ServerBuilder { self.listen_uds(name, lst, factory) } - /// Add new unix domain service to the server. + /// Adds new service to the server using a UDS (unix domain socket) listener already bound. /// /// Useful when running as a systemd service and a socket FD is acquired externally. + /// + /// # Worker Count + /// + /// The `factory` will be instantiated multiple times in most scenarios. The number of + /// instantiations is: number of [`workers`](Self::workers()). pub fn listen_uds>( mut self, name: N, @@ -284,17 +323,22 @@ impl ServerBuilder { F: ServerServiceFactory, { use std::net::{IpAddr, Ipv4Addr}; + lst.set_nonblocking(true)?; + let token = self.next_token(); let addr = crate::socket::StdSocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); + self.factories.push(StreamNewService::create( name.as_ref().to_string(), token, factory, addr, )); + self.sockets .push((token, name.as_ref().to_string(), MioListener::from(lst))); + Ok(self) } } diff --git a/justfile b/justfile index 05c641c2..f2e449d8 100644 --- a/justfile +++ b/justfile @@ -1,2 +1,11 @@ _list: @just --list + +# Document crates in workspace. +doc: + RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl + +# Document crates in workspace and watch for changes. +doc-watch: + RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl --open + cargo watch -- RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl