Skip to main content

ntex_server/
pool.rs

1use ntex_util::time::Millis;
2
3use crate::{Affinity, LoadBalancing, Server, ServerConfiguration, manager::ServerManager};
4
5const DEFAULT_SHUTDOWN_TIMEOUT: Millis = Millis::from_secs(30);
6
7#[allow(clippy::struct_excessive_bools)]
8#[derive(Debug, Clone)]
9/// Builder for a pool of server workers.
10pub struct WorkerPool {
11    pub(crate) num: usize,
12    pub(crate) name: String,
13    pub(crate) no_signals: bool,
14    pub(crate) stop_runtime: bool,
15    pub(crate) stop_on_panic: bool,
16    pub(crate) graceful_shutdown: bool,
17    pub(crate) graceful_shutdown_timeout: Millis,
18    pub(crate) affinity: Affinity,
19    pub(crate) balancing: LoadBalancing,
20}
21
22impl Default for WorkerPool {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl WorkerPool {
29    #[must_use]
30    /// Creates a worker pool with default settings.
31    pub fn new() -> Self {
32        let num = crate::affinity::cpu_count();
33
34        WorkerPool {
35            num,
36            name: "ntex".to_string(),
37            no_signals: false,
38            stop_runtime: false,
39            stop_on_panic: false,
40            graceful_shutdown: false,
41            graceful_shutdown_timeout: DEFAULT_SHUTDOWN_TIMEOUT,
42            affinity: Affinity::default(),
43            balancing: LoadBalancing::IncomingCpu,
44        }
45    }
46
47    #[must_use]
48    /// Sets the worker thread name prefix.
49    ///
50    /// The configured name is used for worker thread names.
51    pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
52        self.name = name.as_ref().to_string();
53        self
54    }
55
56    #[must_use]
57    /// Sets the number of worker threads to start.
58    ///
59    /// By default, the server uses the number of available logical CPUs.
60    pub fn workers(mut self, num: usize) -> Self {
61        self.num = num;
62        self
63    }
64
65    #[must_use]
66    /// Stops the current ntex runtime after the server has stopped.
67    ///
68    /// By default, "stop runtime" is disabled.
69    pub fn stop_runtime(mut self) -> Self {
70        self.stop_runtime = true;
71        self
72    }
73
74    #[must_use]
75    /// Stops the server when one of the workers fails.
76    ///
77    /// A worker fails when it panics or its service cannot be created. The
78    /// stop is graceful only if [`graceful_shutdown`](Self::graceful_shutdown)
79    /// is enabled. Without this option, a failed worker is restarted.
80    ///
81    /// By default, "stop on panic" is disabled.
82    pub fn stop_on_panic(mut self) -> Self {
83        self.stop_on_panic = true;
84        self
85    }
86
87    #[must_use]
88    /// Disables signal handling.
89    ///
90    /// By default, the server stops on SIGINT, SIGTERM, and SIGQUIT.
91    pub fn disable_signals(mut self) -> Self {
92        self.no_signals = true;
93        self
94    }
95
96    #[must_use]
97    /// Enables graceful shutdown on SIGQUIT, fatal signals, and panics.
98    ///
99    /// When enabled, SIGQUIT, SIGSEGV, SIGABRT, application panics, and
100    /// worker failures with "stop on panic" stop the server gracefully.
101    /// SIGTERM always stops gracefully and SIGINT always stops immediately.
102    ///
103    /// By default, these events stop the server immediately.
104    pub fn graceful_shutdown(mut self) -> Self {
105        self.graceful_shutdown = true;
106        self
107    }
108
109    #[must_use]
110    /// Timeout for graceful worker shutdown.
111    ///
112    /// After receiving a stop signal, workers have this much time to finish
113    /// serving requests. Workers that are still alive after the timeout are
114    /// forcefully dropped.
115    ///
116    /// This bounds the worker as a whole, not an individual connection. Each
117    /// connection is bound separately by `IoConfig::set_shutdown_timeout`, so
118    /// this value should leave room for the connections a worker is still
119    /// draining to shut down themselves.
120    ///
121    /// By default, the timeout is set to 30 seconds.
122    pub fn graceful_shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
123        self.graceful_shutdown_timeout = timeout.into();
124        self
125    }
126
127    #[must_use]
128    #[deprecated(
129        since = "4.3.0",
130        note = "affinity is enabled by default, use `affinity()` to change it"
131    )]
132    /// Does nothing, affinity is enabled by default.
133    pub fn enable_affinity(self) -> Self {
134        self
135    }
136
137    #[must_use]
138    /// Sets the CPU affinity of worker threads.
139    ///
140    /// Workers are spread over physical cores first, see [`Affinity`].
141    ///
142    /// By default, [`Affinity::Soft`] is used on Windows and
143    /// [`Affinity::Core`] on other platforms.
144    pub fn affinity(mut self, affinity: Affinity) -> Self {
145        self.affinity = affinity;
146        self
147    }
148
149    #[must_use]
150    /// Sets how items are distributed between workers.
151    ///
152    /// By default, [`LoadBalancing::IncomingCpu`] sends new items to idle
153    /// workers, which helps when connections are long-lived or their load is
154    /// uneven, and prefers the worker on the CPU that receives a connection's
155    /// network packets. [`LoadBalancing::RoundRobin`] sends them to the
156    /// workers in turn.
157    pub fn load_balancing(mut self, balancing: LoadBalancing) -> Self {
158        self.balancing = balancing;
159        self
160    }
161
162    /// Starts processing incoming items and returns a server controller.
163    pub fn run<F: ServerConfiguration>(self, factory: F) -> Server<F::Item> {
164        ServerManager::start(self, factory)
165    }
166}