Skip to main content

actix_server/
server.rs

1use std::{
2    future::Future,
3    io, mem,
4    pin::Pin,
5    task::{Context, Poll},
6    thread,
7    time::Duration,
8};
9
10use actix_rt::{time::sleep, System};
11use futures_core::{future::BoxFuture, Stream};
12use futures_util::stream::StreamExt as _;
13use tokio::sync::{mpsc::UnboundedReceiver, oneshot, watch};
14use tracing::{error, info};
15
16use crate::{
17    accept::Accept,
18    builder::ServerBuilder,
19    join_all::join_all,
20    service::InternalServiceFactory,
21    signals::{OsSignals, SignalKind, StopSignal},
22    waker_queue::{WakerInterest, WakerQueue},
23    worker::{ServerWorker, ServerWorkerConfig, WorkerHandleServer},
24    ServerHandle,
25};
26
27#[derive(Debug)]
28pub(crate) enum ServerCommand {
29    /// Worker failed to accept connection, indicating a probable panic.
30    ///
31    /// Contains index of faulted worker.
32    WorkerFaulted(usize),
33
34    /// Pause accepting connections.
35    ///
36    /// Contains return channel to notify caller of successful state change.
37    Pause(oneshot::Sender<()>),
38
39    /// Resume accepting connections.
40    ///
41    /// Contains return channel to notify caller of successful state change.
42    Resume(oneshot::Sender<()>),
43
44    /// Stop accepting connections and begin shutdown procedure.
45    Stop {
46        /// True if shut down should be graceful.
47        graceful: bool,
48
49        /// Return channel to notify caller that shutdown is complete.
50        completion: Option<oneshot::Sender<()>>,
51
52        /// Force System exit when true, overriding `ServerBuilder::system_exit()` if it is false.
53        force_system_stop: bool,
54    },
55}
56
57/// General purpose TCP server that runs services receiving Tokio `TcpStream`s.
58///
59/// Handles creating worker threads, restarting faulted workers, connection accepting, and
60/// back-pressure logic.
61///
62/// Creates a worker per CPU core (or the number specified in [`ServerBuilder::workers`]) and
63/// distributes connections with a round-robin strategy.
64///
65/// The [Server] must be awaited or polled in order to start running. It will resolve when the
66/// server has fully shut down.
67///
68/// # Shutdown Signals
69/// On UNIX systems, `SIGTERM` will start a graceful shutdown and `SIGQUIT` or `SIGINT` will start a
70/// forced shutdown. On Windows, a Ctrl-C signal will start a forced shutdown.
71///
72/// A graceful shutdown will wait for all workers to stop first.
73///
74/// # Examples
75/// The following is a TCP echo server. Test using `telnet 127.0.0.1 8080`.
76///
77/// ```no_run
78/// use std::io;
79///
80/// use actix_rt::net::TcpStream;
81/// use actix_server::Server;
82/// use actix_service::{fn_service, ServiceFactoryExt as _};
83/// use bytes::BytesMut;
84/// use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
85///
86/// #[actix_rt::main]
87/// async fn main() -> io::Result<()> {
88///     let bind_addr = ("127.0.0.1", 8080);
89///
90///     Server::build()
91///         .bind("echo", bind_addr, move || {
92///             fn_service(move |mut stream: TcpStream| {
93///                 async move {
94///                     let mut size = 0;
95///                     let mut buf = BytesMut::new();
96///
97///                     loop {
98///                         match stream.read_buf(&mut buf).await {
99///                             // end of stream; bail from loop
100///                             Ok(0) => break,
101///
102///                             // write bytes back to stream
103///                             Ok(bytes_read) => {
104///                                 stream.write_all(&buf[size..]).await.unwrap();
105///                                 size += bytes_read;
106///                             }
107///
108///                             Err(err) => {
109///                                 eprintln!("Stream Error: {:?}", err);
110///                                 return Err(());
111///                             }
112///                         }
113///                     }
114///
115///                     Ok(())
116///                 }
117///             })
118///             .map_err(|err| eprintln!("Service Error: {:?}", err))
119///         })?
120///         .run()
121///         .await
122/// }
123/// ```
124#[must_use = "Server does nothing unless you `.await` or poll it"]
125pub struct Server {
126    handle: ServerHandle,
127    fut: BoxFuture<'static, io::Result<()>>,
128}
129
130impl Server {
131    /// Create server build.
132    pub fn build() -> ServerBuilder {
133        ServerBuilder::default()
134    }
135
136    pub(crate) fn new(builder: ServerBuilder) -> Self {
137        Server {
138            handle: ServerHandle::new(builder.cmd_tx.clone()),
139            fut: Box::pin(ServerInner::run(builder)),
140        }
141    }
142
143    /// Get a `Server` handle that can be used issue commands and change it's state.
144    ///
145    /// See [ServerHandle](ServerHandle) for usage.
146    pub fn handle(&self) -> ServerHandle {
147        self.handle.clone()
148    }
149}
150
151impl Future for Server {
152    type Output = io::Result<()>;
153
154    #[inline]
155    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
156        Pin::new(&mut Pin::into_inner(self).fut).poll(cx)
157    }
158}
159
160pub struct ServerInner {
161    worker_handles: Vec<WorkerHandleServer>,
162    accept_handle: Option<thread::JoinHandle<()>>,
163    worker_config: ServerWorkerConfig,
164    services: Vec<Box<dyn InternalServiceFactory>>,
165    waker_queue: WakerQueue,
166    system_stop: bool,
167    stopping: bool,
168    graceful_shutdown_tx: watch::Sender<()>,
169}
170
171impl ServerInner {
172    async fn run(builder: ServerBuilder) -> io::Result<()> {
173        let (mut this, mut mux) = Self::run_sync(builder)?;
174
175        while let Some(cmd) = mux.next().await {
176            this.handle_cmd(cmd).await;
177
178            if this.stopping {
179                break;
180            }
181        }
182
183        Ok(())
184    }
185
186    fn run_sync(mut builder: ServerBuilder) -> io::Result<(Self, ServerEventMultiplexer)> {
187        // Give log information on what runtime will be used.
188        let is_actix = actix_rt::System::try_current().is_some();
189        let is_tokio = tokio::runtime::Handle::try_current().is_ok();
190
191        match (is_actix, is_tokio) {
192            (true, _) => info!("Actix runtime found; starting in Actix runtime"),
193            (_, true) => info!("Tokio runtime found; starting in existing Tokio runtime"),
194            (_, false) => panic!("Actix or Tokio runtime not found; halting"),
195        }
196
197        for (_, name, lst) in &builder.sockets {
198            info!(
199                r#"starting service: "{}", workers: {}, listening on: {}"#,
200                name,
201                builder.threads,
202                lst.local_addr()
203            );
204        }
205
206        let sockets = mem::take(&mut builder.sockets)
207            .into_iter()
208            .map(|t| (t.0, t.2))
209            .collect();
210
211        let (waker_queue, worker_handles, accept_handle) = Accept::start(sockets, &builder)?;
212
213        let mux = ServerEventMultiplexer {
214            signal_fut: builder.shutdown_signal.map(StopSignal::Cancel).or_else(|| {
215                builder
216                    .listen_os_signals
217                    .then(OsSignals::new)
218                    .map(StopSignal::Os)
219            }),
220            cmd_rx: builder.cmd_rx,
221        };
222
223        let server = ServerInner {
224            waker_queue,
225            accept_handle: Some(accept_handle),
226            worker_handles,
227            worker_config: builder.worker_config,
228            services: builder.factories,
229            system_stop: builder.exit,
230            stopping: false,
231            graceful_shutdown_tx: builder.graceful_shutdown_tx,
232        };
233
234        Ok((server, mux))
235    }
236
237    async fn handle_cmd(&mut self, item: ServerCommand) {
238        match item {
239            ServerCommand::Pause(tx) => {
240                self.waker_queue.wake(WakerInterest::Pause);
241                let _ = tx.send(());
242            }
243
244            ServerCommand::Resume(tx) => {
245                self.waker_queue.wake(WakerInterest::Resume);
246                let _ = tx.send(());
247            }
248
249            ServerCommand::Stop {
250                graceful,
251                completion,
252                force_system_stop,
253            } => {
254                self.stopping = true;
255
256                if graceful {
257                    self.graceful_shutdown_tx.send_replace(());
258                }
259
260                // Signal accept thread to stop.
261                // Signal is non-blocking; we wait for thread to stop later.
262                self.waker_queue.wake(WakerInterest::Stop);
263
264                // send stop signal to workers
265                let workers_stop = self
266                    .worker_handles
267                    .iter()
268                    .map(|worker| worker.stop(graceful))
269                    .collect::<Vec<_>>();
270
271                if graceful {
272                    // wait for all workers to shut down
273                    let _ = join_all(workers_stop).await;
274                }
275
276                // wait for accept thread stop
277                self.accept_handle
278                    .take()
279                    .unwrap()
280                    .join()
281                    .expect("Accept thread must not panic in any case");
282
283                if let Some(tx) = completion {
284                    let _ = tx.send(());
285                }
286
287                if self.system_stop || force_system_stop {
288                    sleep(Duration::from_millis(300)).await;
289                    System::try_current().as_ref().map(System::stop);
290                }
291            }
292
293            ServerCommand::WorkerFaulted(idx) => {
294                // TODO: maybe just return with warning log if not found ?
295                assert!(self.worker_handles.iter().any(|wrk| wrk.idx == idx));
296
297                error!("worker {} has died; restarting", idx);
298
299                let factories = self
300                    .services
301                    .iter()
302                    .map(|service| service.clone_factory())
303                    .collect();
304
305                match ServerWorker::start(
306                    idx,
307                    factories,
308                    self.waker_queue.clone(),
309                    self.worker_config,
310                ) {
311                    Ok((handle_accept, handle_server)) => {
312                        *self
313                            .worker_handles
314                            .iter_mut()
315                            .find(|wrk| wrk.idx == idx)
316                            .unwrap() = handle_server;
317
318                        self.waker_queue.wake(WakerInterest::Worker(handle_accept));
319                    }
320
321                    Err(err) => error!("can not restart worker {}: {}", idx, err),
322                };
323            }
324        }
325    }
326
327    fn map_signal(signal: SignalKind) -> ServerCommand {
328        match signal {
329            SignalKind::Cancel => {
330                info!("Cancellation token/channel received; starting graceful shutdown");
331                ServerCommand::Stop {
332                    graceful: true,
333                    completion: None,
334                    force_system_stop: true,
335                }
336            }
337
338            SignalKind::OsInt => {
339                info!("SIGINT received; starting forced shutdown");
340                ServerCommand::Stop {
341                    graceful: false,
342                    completion: None,
343                    force_system_stop: true,
344                }
345            }
346
347            SignalKind::OsTerm => {
348                info!("SIGTERM received; starting graceful shutdown");
349                ServerCommand::Stop {
350                    graceful: true,
351                    completion: None,
352                    force_system_stop: true,
353                }
354            }
355
356            SignalKind::OsQuit => {
357                info!("SIGQUIT received; starting forced shutdown");
358                ServerCommand::Stop {
359                    graceful: false,
360                    completion: None,
361                    force_system_stop: true,
362                }
363            }
364        }
365    }
366}
367
368struct ServerEventMultiplexer {
369    cmd_rx: UnboundedReceiver<ServerCommand>,
370    signal_fut: Option<StopSignal>,
371}
372
373impl Stream for ServerEventMultiplexer {
374    type Item = ServerCommand;
375
376    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
377        let this = Pin::into_inner(self);
378
379        if let Some(signal_fut) = &mut this.signal_fut {
380            if let Poll::Ready(signal) = Pin::new(signal_fut).poll(cx) {
381                this.signal_fut = None;
382                return Poll::Ready(Some(ServerInner::map_signal(signal)));
383            }
384        }
385
386        this.cmd_rx.poll_recv(cx)
387    }
388}