1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-06-28 12:10:37 +02: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
8 changed files with 63 additions and 39 deletions

View File

@ -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(());
}

View File

@ -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<oneshot::Sender<()>>,
},
@ -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<ServerCommand>,

View File

@ -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() {

View File

@ -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<F>(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<F: ServiceFactory<TcpStream>>(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> {
TcpStream::from_std(net::TcpStream::connect(self.addr)?)
}

View File

@ -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<Box<Sleep>>,
/// Start time of shutdown.
start_from: Instant,
/// Notify of the shutdown outcome (force/grace) to stop caller.
tx: oneshot::Sender<bool>,
}
@ -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)