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