1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-02-17 14:43:31 +01:00

prepare actix-server release 2.0.0-beta.6

This commit is contained in:
Rob Ede 2021-10-11 05:14:34 +01:00
parent 9fa8d7fc5a
commit ca435b2575
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
8 changed files with 63 additions and 39 deletions

View File

@ -1,13 +1,15 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## 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] * Add `io-uring` feature for enabling async file I/O on linux. [#374]
* Server no long listens to SIGHUP signal. * Server no long listens to `SIGHUP` signal. Previously, the received was not used but did block
It actually did not take any action when receiving SIGHUP, the only thing SIGHUP did was to stop subsequent exit signals from working. [#389]
the Server from receiving any future signal, because the `Signals` future stops on the first * Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to
signal received [#389] this change. [#349]
* Remove `ServerBuilder::configure` [#349]
[#374]: https://github.com/actix/actix-net/pull/374 [#374]: https://github.com/actix/actix-net/pull/374
[#349]: https://github.com/actix/actix-net/pull/349 [#349]: https://github.com/actix/actix-net/pull/349
@ -15,9 +17,9 @@
## 2.0.0-beta.5 - 2021-04-20 ## 2.0.0-beta.5 - 2021-04-20
* Server shutdown would notify all workers to exit regardless if shutdown is graceful. * Server shutdown notifies all workers to exit regardless if shutdown is graceful. This causes all
This would make all worker shutdown immediately in force shutdown case. [#333] workers to shutdown immediately in force shutdown case. [#333]
[#333]: https://github.com/actix/actix-net/pull/333 [#333]: https://github.com/actix/actix-net/pull/333

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-server" name = "actix-server"
version = "2.0.0-beta.5" version = "2.0.0-beta.6"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"fakeshadow <24548779@qq.com>", "fakeshadow <24548779@qq.com>",

View File

@ -312,23 +312,25 @@ impl ServerBuilder {
// Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system // Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system
match sig { match sig {
Signal::Int => { Signal::Int => {
info!("SIGINT received, exiting"); info!("SIGINT received, starting forced shutdown");
self.exit = true; self.exit = true;
self.handle_cmd(ServerCommand::Stop { self.handle_cmd(ServerCommand::Stop {
graceful: false, graceful: false,
completion: None, completion: None,
}) })
} }
Signal::Term => { Signal::Term => {
info!("SIGTERM received, stopping"); info!("SIGTERM received, starting graceful shutdown");
self.exit = true; self.exit = true;
self.handle_cmd(ServerCommand::Stop { self.handle_cmd(ServerCommand::Stop {
graceful: true, graceful: true,
completion: None, completion: None,
}) })
} }
Signal::Quit => { Signal::Quit => {
info!("SIGQUIT received, exiting"); info!("SIGQUIT received, starting forced shutdown");
self.exit = true; self.exit = true;
self.handle_cmd(ServerCommand::Stop { self.handle_cmd(ServerCommand::Stop {
graceful: false, graceful: false,
@ -359,12 +361,14 @@ impl ServerBuilder {
rt::spawn(async move { rt::spawn(async move {
if graceful { if graceful {
// wait for all workers to shut down
let _ = join_all(stop).await; let _ = join_all(stop).await;
} }
if let Some(tx) = completion { if let Some(tx) = completion {
let _ = tx.send(()); let _ = tx.send(());
} }
for tx in notify { for tx in notify {
let _ = tx.send(()); let _ = tx.send(());
} }

View File

@ -15,8 +15,8 @@ pub(crate) enum ServerCommand {
Pause(oneshot::Sender<()>), Pause(oneshot::Sender<()>),
Resume(oneshot::Sender<()>), Resume(oneshot::Sender<()>),
Signal(Signal), Signal(Signal),
/// Whether to try and shut down gracefully
Stop { Stop {
/// True if shut down should be graceful.
graceful: bool, graceful: bool,
completion: Option<oneshot::Sender<()>>, completion: Option<oneshot::Sender<()>>,
}, },
@ -24,6 +24,13 @@ pub(crate) enum ServerCommand {
Notify(oneshot::Sender<()>), 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)] #[derive(Debug)]
pub struct Server( pub struct Server(
UnboundedSender<ServerCommand>, UnboundedSender<ServerCommand>,

View File

@ -4,27 +4,33 @@ use std::task::{Context, Poll};
use crate::server::Server; use crate::server::Server;
/// Different types of process signals /// Types of process signals.
#[allow(dead_code)] #[allow(dead_code)]
#[derive(PartialEq, Clone, Copy, Debug)] #[derive(PartialEq, Clone, Copy, Debug)]
pub(crate) enum Signal { pub(crate) enum Signal {
/// SIGINT /// `SIGINT`
Int, Int,
/// SIGTERM
/// `SIGTERM`
Term, Term,
/// SIGQUIT
/// `SIGQUIT`
Quit, Quit,
} }
/// Process signal listener.
pub(crate) struct Signals { pub(crate) struct Signals {
srv: Server, srv: Server,
#[cfg(not(unix))] #[cfg(not(unix))]
signals: futures_core::future::LocalBoxFuture<'static, std::io::Result<()>>, signals: futures_core::future::LocalBoxFuture<'static, std::io::Result<()>>,
#[cfg(unix)] #[cfg(unix)]
signals: Vec<(Signal, actix_rt::signal::unix::Signal)>, signals: Vec<(Signal, actix_rt::signal::unix::Signal)>,
} }
impl Signals { impl Signals {
/// Spawns a signal listening future that is able to send commands to the `Server`.
pub(crate) fn start(srv: Server) { pub(crate) fn start(srv: Server) {
#[cfg(not(unix))] #[cfg(not(unix))]
{ {
@ -33,6 +39,7 @@ impl Signals {
signals: Box::pin(actix_rt::signal::ctrl_c()), signals: Box::pin(actix_rt::signal::ctrl_c()),
}); });
} }
#[cfg(unix)] #[cfg(unix)]
{ {
use actix_rt::signal::unix; use actix_rt::signal::unix;
@ -76,6 +83,7 @@ impl Future for Signals {
} }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
#[cfg(unix)] #[cfg(unix)]
{ {
for (sig, fut) in self.signals.iter_mut() { for (sig, fut) in self.signals.iter_mut() {

View File

@ -5,13 +5,12 @@ use actix_rt::{net::TcpStream, System};
use crate::{Server, ServerBuilder, ServiceFactory}; use crate::{Server, ServerBuilder, ServiceFactory};
/// The `TestServer` type. /// A testing server.
/// ///
/// `TestServer` is very simple test server that simplify process of writing /// `TestServer` is very simple test server that simplify process of writing integration tests for
/// integration tests for actix-net applications. /// network applications.
/// ///
/// # Examples /// # Examples
///
/// ``` /// ```
/// use actix_service::fn_service; /// use actix_service::fn_service;
/// use actix_server::TestServer; /// use actix_server::TestServer;
@ -39,7 +38,7 @@ pub struct TestServerRuntime {
} }
impl TestServer { impl TestServer {
/// Start new server with server builder /// Start new server with server builder.
pub fn start<F>(mut factory: F) -> TestServerRuntime pub fn start<F>(mut factory: F) -> TestServerRuntime
where where
F: FnMut(ServerBuilder) -> ServerBuilder + Send + 'static, 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<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime { pub fn with<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime {
let (tx, rx) = mpsc::channel(); 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 { pub fn unused_addr() -> net::SocketAddr {
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
let socket = mio::net::TcpSocket::new_v4().unwrap(); let socket = mio::net::TcpSocket::new_v4().unwrap();
@ -111,27 +110,27 @@ impl TestServer {
} }
impl TestServerRuntime { impl TestServerRuntime {
/// Test server host /// Test server host.
pub fn host(&self) -> &str { pub fn host(&self) -> &str {
&self.host &self.host
} }
/// Test server port /// Test server port.
pub fn port(&self) -> u16 { pub fn port(&self) -> u16 {
self.port self.port
} }
/// Get test server address /// Get test server address.
pub fn addr(&self) -> net::SocketAddr { pub fn addr(&self) -> net::SocketAddr {
self.addr self.addr
} }
/// Stop http server /// Stop server.
fn stop(&mut self) { fn stop(&mut self) {
self.system.stop(); self.system.stop();
} }
/// Connect to server, return tokio TcpStream /// Connect to server, returning a Tokio `TcpStream`.
pub fn connect(&self) -> std::io::Result<TcpStream> { pub fn connect(&self) -> std::io::Result<TcpStream> {
TcpStream::from_std(net::TcpStream::connect(self.addr)?) TcpStream::from_std(net::TcpStream::connect(self.addr)?)
} }

View File

@ -429,13 +429,15 @@ struct Restart {
fut: LocalBoxFuture<'static, Result<(usize, BoxedServerService), ()>>, fut: LocalBoxFuture<'static, Result<(usize, BoxedServerService), ()>>,
} }
// Shutdown keep states necessary for server shutdown: /// State 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.
struct Shutdown { struct Shutdown {
// Interval for checking the shutdown progress.
timer: Pin<Box<Sleep>>, timer: Pin<Box<Sleep>>,
/// Start time of shutdown.
start_from: Instant, start_from: Instant,
/// Notify of the shutdown outcome (force/grace) to stop caller.
tx: oneshot::Sender<bool>, tx: oneshot::Sender<bool>,
} }
@ -521,23 +523,25 @@ impl Future for ServerWorker {
self.poll(cx) self.poll(cx)
} }
WorkerState::Shutdown(ref mut shutdown) => { WorkerState::Shutdown(ref mut shutdown) => {
// Wait for 1 second. // wait for 1 second
ready!(shutdown.timer.as_mut().poll(cx)); ready!(shutdown.timer.as_mut().poll(cx));
if this.counter.total() == 0 { if this.counter.total() == 0 {
// Graceful shutdown. // graceful shutdown
if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) { if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) {
let _ = shutdown.tx.send(true); let _ = shutdown.tx.send(true);
} }
Poll::Ready(()) Poll::Ready(())
} else if shutdown.start_from.elapsed() >= this.shutdown_timeout { } 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) { if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) {
let _ = shutdown.tx.send(false); let _ = shutdown.tx.send(false);
} }
Poll::Ready(()) Poll::Ready(())
} else { } else {
// Reset timer and wait for 1 second. // reset timer and wait for 1 second
let time = Instant::now() + Duration::from_secs(1); let time = Instant::now() + Duration::from_secs(1);
shutdown.timer.as_mut().reset(time); shutdown.timer.as_mut().reset(time);
shutdown.timer.as_mut().poll(cx) shutdown.timer.as_mut().poll(cx)

View File

@ -64,7 +64,7 @@ tokio-native-tls = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
actix-rt = "2.2.0" actix-rt = "2.2.0"
actix-server = "2.0.0-beta.5" actix-server = "2.0.0-beta.6"
bytes = "1" bytes = "1"
env_logger = "0.8" env_logger = "0.8"
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }