diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 69f5b08c..6b080daf 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -1,13 +1,15 @@ # Changes ## Unreleased - 2021-xx-xx -* Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to this change. [#349] -* Remove `ServerBuilder::configure` [#349] + + +## 2.0.0-beta.6 - 2021-10-11 * Add `io-uring` feature for enabling async file I/O on linux. [#374] -* Server no long listens to SIGHUP signal. - It actually did not take any action when receiving SIGHUP, the only thing SIGHUP did was to stop - the Server from receiving any future signal, because the `Signals` future stops on the first - signal received [#389] +* Server no long listens to `SIGHUP` signal. Previously, the received was not used but did block + subsequent exit signals from working. [#389] +* Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to + this change. [#349] +* Remove `ServerBuilder::configure` [#349] [#374]: https://github.com/actix/actix-net/pull/374 [#349]: https://github.com/actix/actix-net/pull/349 @@ -15,9 +17,9 @@ ## 2.0.0-beta.5 - 2021-04-20 -* Server shutdown would notify all workers to exit regardless if shutdown is graceful. - This would make all worker shutdown immediately in force shutdown case. [#333] - +* Server shutdown notifies all workers to exit regardless if shutdown is graceful. This causes all + workers to shutdown immediately in force shutdown case. [#333] + [#333]: https://github.com/actix/actix-net/pull/333 diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index 92d5a25b..8fd3112b 100755 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-server" -version = "2.0.0-beta.5" +version = "2.0.0-beta.6" authors = [ "Nikolay Kim ", "fakeshadow <24548779@qq.com>", diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index 46a55ef4..871abb5b 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -312,23 +312,25 @@ impl ServerBuilder { // Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system match sig { Signal::Int => { - info!("SIGINT received, exiting"); + info!("SIGINT received, starting forced shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: false, completion: None, }) } + Signal::Term => { - info!("SIGTERM received, stopping"); + info!("SIGTERM received, starting graceful shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: true, completion: None, }) } + Signal::Quit => { - info!("SIGQUIT received, exiting"); + info!("SIGQUIT received, starting forced shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: false, @@ -359,12 +361,14 @@ impl ServerBuilder { rt::spawn(async move { if graceful { + // wait for all workers to shut down let _ = join_all(stop).await; } if let Some(tx) = completion { let _ = tx.send(()); } + for tx in notify { let _ = tx.send(()); } diff --git a/actix-server/src/server.rs b/actix-server/src/server.rs index 6b0d0aea..f0dfca0b 100644 --- a/actix-server/src/server.rs +++ b/actix-server/src/server.rs @@ -15,8 +15,8 @@ pub(crate) enum ServerCommand { Pause(oneshot::Sender<()>), Resume(oneshot::Sender<()>), Signal(Signal), - /// Whether to try and shut down gracefully Stop { + /// True if shut down should be graceful. graceful: bool, completion: Option>, }, @@ -24,6 +24,13 @@ pub(crate) enum ServerCommand { Notify(oneshot::Sender<()>), } +/// Server handle. +/// +/// # Shutdown Signals +/// On UNIX systems, `SIGQUIT` will start a graceful shutdown and `SIGTERM` or `SIGINT` will start a +/// forced shutdown. On Windows, a CTRL-C signal will start a forced shutdown. +/// +/// A graceful shutdown will wait for all workers to stop first. #[derive(Debug)] pub struct Server( UnboundedSender, diff --git a/actix-server/src/signals.rs b/actix-server/src/signals.rs index cdd96b9c..c9cdb45e 100644 --- a/actix-server/src/signals.rs +++ b/actix-server/src/signals.rs @@ -4,27 +4,33 @@ use std::task::{Context, Poll}; use crate::server::Server; -/// Different types of process signals +/// Types of process signals. #[allow(dead_code)] #[derive(PartialEq, Clone, Copy, Debug)] pub(crate) enum Signal { - /// SIGINT + /// `SIGINT` Int, - /// SIGTERM + + /// `SIGTERM` Term, - /// SIGQUIT + + /// `SIGQUIT` Quit, } +/// Process signal listener. pub(crate) struct Signals { srv: Server, + #[cfg(not(unix))] signals: futures_core::future::LocalBoxFuture<'static, std::io::Result<()>>, + #[cfg(unix)] signals: Vec<(Signal, actix_rt::signal::unix::Signal)>, } impl Signals { + /// Spawns a signal listening future that is able to send commands to the `Server`. pub(crate) fn start(srv: Server) { #[cfg(not(unix))] { @@ -33,6 +39,7 @@ impl Signals { signals: Box::pin(actix_rt::signal::ctrl_c()), }); } + #[cfg(unix)] { use actix_rt::signal::unix; @@ -76,6 +83,7 @@ impl Future for Signals { } Poll::Pending => Poll::Pending, } + #[cfg(unix)] { for (sig, fut) in self.signals.iter_mut() { diff --git a/actix-server/src/test_server.rs b/actix-server/src/test_server.rs index 0611cf4b..ad6ee8ee 100644 --- a/actix-server/src/test_server.rs +++ b/actix-server/src/test_server.rs @@ -5,13 +5,12 @@ use actix_rt::{net::TcpStream, System}; use crate::{Server, ServerBuilder, ServiceFactory}; -/// The `TestServer` type. +/// A testing server. /// -/// `TestServer` is very simple test server that simplify process of writing -/// integration tests for actix-net applications. +/// `TestServer` is very simple test server that simplify process of writing integration tests for +/// network applications. /// /// # Examples -/// /// ``` /// use actix_service::fn_service; /// use actix_server::TestServer; @@ -39,7 +38,7 @@ pub struct TestServerRuntime { } impl TestServer { - /// Start new server with server builder + /// Start new server with server builder. pub fn start(mut factory: F) -> TestServerRuntime where F: FnMut(ServerBuilder) -> ServerBuilder + Send + 'static, @@ -64,7 +63,7 @@ impl TestServer { } } - /// Start new test server with application factory + /// Start new test server with application factory. pub fn with>(factory: F) -> TestServerRuntime { let (tx, rx) = mpsc::channel(); @@ -99,7 +98,7 @@ impl TestServer { } } - /// Get first available unused local address + /// Get first available unused local address. pub fn unused_addr() -> net::SocketAddr { let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); let socket = mio::net::TcpSocket::new_v4().unwrap(); @@ -111,27 +110,27 @@ impl TestServer { } impl TestServerRuntime { - /// Test server host + /// Test server host. pub fn host(&self) -> &str { &self.host } - /// Test server port + /// Test server port. pub fn port(&self) -> u16 { self.port } - /// Get test server address + /// Get test server address. pub fn addr(&self) -> net::SocketAddr { self.addr } - /// Stop http server + /// Stop server. fn stop(&mut self) { self.system.stop(); } - /// Connect to server, return tokio TcpStream + /// Connect to server, returning a Tokio `TcpStream`. pub fn connect(&self) -> std::io::Result { TcpStream::from_std(net::TcpStream::connect(self.addr)?) } diff --git a/actix-server/src/worker.rs b/actix-server/src/worker.rs index 21f98027..b99b2da2 100644 --- a/actix-server/src/worker.rs +++ b/actix-server/src/worker.rs @@ -429,13 +429,15 @@ struct Restart { fut: LocalBoxFuture<'static, Result<(usize, BoxedServerService), ()>>, } -// Shutdown keep states necessary for server shutdown: -// Sleep for interval check the shutdown progress. -// Instant for the start time of shutdown. -// Sender for send back the shutdown outcome(force/grace) to StopCommand caller. +/// State necessary for server shutdown. struct Shutdown { + // Interval for checking the shutdown progress. timer: Pin>, + + /// Start time of shutdown. start_from: Instant, + + /// Notify of the shutdown outcome (force/grace) to stop caller. tx: oneshot::Sender, } @@ -521,23 +523,25 @@ impl Future for ServerWorker { self.poll(cx) } WorkerState::Shutdown(ref mut shutdown) => { - // Wait for 1 second. + // wait for 1 second ready!(shutdown.timer.as_mut().poll(cx)); if this.counter.total() == 0 { - // Graceful shutdown. + // graceful shutdown if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) { let _ = shutdown.tx.send(true); } + Poll::Ready(()) } else if shutdown.start_from.elapsed() >= this.shutdown_timeout { - // Timeout forceful shutdown. + // timeout forceful shutdown if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) { let _ = shutdown.tx.send(false); } + Poll::Ready(()) } else { - // Reset timer and wait for 1 second. + // reset timer and wait for 1 second let time = Instant::now() + Duration::from_secs(1); shutdown.timer.as_mut().reset(time); shutdown.timer.as_mut().poll(cx) diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index 9fa260c7..00082278 100755 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -64,7 +64,7 @@ tokio-native-tls = { version = "0.3", optional = true } [dev-dependencies] actix-rt = "2.2.0" -actix-server = "2.0.0-beta.5" +actix-server = "2.0.0-beta.6" bytes = "1" env_logger = "0.8" futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }