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}