ntex_server/lib.rs
1//! Worker-based server infrastructure for ntex.
2//!
3//! [`WorkerPool`] runs services across one or more worker threads. The [`net`]
4//! module builds TCP and Unix domain socket servers on top of that pool.
5//! [`Server`] is the controller used to pause, resume, stop, or await a running
6//! server.
7
8#![deny(clippy::pedantic)]
9#![allow(
10 async_fn_in_trait,
11 clippy::clone_on_copy,
12 clippy::must_use_candidate,
13 clippy::missing_fields_in_debug,
14 clippy::missing_errors_doc,
15 clippy::missing_panics_doc,
16 clippy::unused_async
17)]
18
19use ntex_service::Service;
20
21mod affinity;
22mod balance;
23mod manager;
24mod metrics;
25pub mod net;
26mod pool;
27mod server;
28mod state;
29mod status;
30mod wrk;
31
32pub use self::affinity::Affinity;
33pub use self::balance::LoadBalancing;
34pub use self::metrics::{ListenerMetrics, RuntimeMetrics, ServerMetrics, WorkerMetrics};
35pub use self::pool::WorkerPool;
36pub use self::server::Server;
37pub use self::state::{NoConfig, ServerAppConfig};
38pub use self::status::ServerStatus;
39pub use self::wrk::{Worker, WorkerStatus, WorkerStop};
40
41/// Identifier assigned to a server worker.
42#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
43pub struct WorkerId(pub(crate) usize);
44
45impl WorkerId {
46 pub(self) fn next(&mut self) -> WorkerId {
47 let id = WorkerId(self.0);
48 self.0 += 1;
49 id
50 }
51}
52
53/// Worker service configuration.
54pub trait ServerConfiguration: Send + Clone + 'static {
55 /// Item dispatched to a worker service.
56 type Item: Send + 'static;
57 /// Service created independently for each worker.
58 type Service: Service<(), Self::Item, Res = (), Error = ()> + 'static;
59
60 /// Creates the service used by one worker.
61 async fn create(&self) -> std::io::Result<Self::Service>;
62
63 /// Called when the server status changes from
64 /// [`Ready`](ServerStatus::Ready) to paused or unavailable.
65 ///
66 /// The server is paused by [`Server::pause`], and it is unavailable
67 /// while no worker can accept items. Not called when the server stops.
68 fn pause(&self) {}
69
70 /// Called when the server status becomes [`Ready`](ServerStatus::Ready).
71 ///
72 /// The server is ready while it is not paused and a worker is available.
73 fn resume(&self) {}
74
75 /// Called when the server's command loop exits.
76 ///
77 /// This happens after a stop requested through [`Server::stop`] or a
78 /// signal, graceful or not, once [`stop`](Self::stop) has completed.
79 fn terminate(&self) {}
80
81 /// Performs asynchronous cleanup when the server stops.
82 ///
83 /// Called once, before the workers are stopped.
84 async fn stop(&self) {}
85
86 /// Returns the index of the logical CPU that receives the network packets
87 /// of the item, if known.
88 ///
89 /// Used by [`LoadBalancing::IncomingCpu`] to send the item to the worker
90 /// placed on that CPU. CPUs are numbered as in [`Worker::start`]. Network
91 /// servers return the receive-side scaling (RSS) CPU of the connection on
92 /// Windows, and its `SO_INCOMING_CPU` on Linux and Android. The default
93 /// returns `None`.
94 ///
95 /// Called on the thread that submits the item with [`Server::process`],
96 /// e.g. the accept thread of a network server.
97 /// Calls are not concurrent. An item submitted while the method runs,
98 /// e.g. by the method itself, is sent without its incoming CPU.
99 fn incoming_cpu(&self, item: &Self::Item) -> Option<usize> {
100 let _ = item;
101 None
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn worker_id_next() {
111 let mut id = WorkerId::default();
112 assert_eq!(id.next(), WorkerId(0));
113 assert_eq!(id.next(), WorkerId(1));
114 assert_eq!(id, WorkerId(2));
115 }
116}