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