1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-25 00:12:59 +01:00
actix-extras/src/server/worker.rs

140 lines
3.9 KiB
Rust
Raw Normal View History

2018-08-09 20:52:32 +02:00
use std::{net, time};
2018-08-03 08:17:10 +02:00
2018-08-09 20:52:32 +02:00
use futures::sync::mpsc::{SendError, UnboundedSender};
2018-05-29 19:31:37 +02:00
use futures::sync::oneshot;
2018-04-29 07:55:47 +02:00
use futures::Future;
2017-12-28 21:38:37 +01:00
2018-06-01 18:36:16 +02:00
use actix::msgs::StopArbiter;
2018-08-09 20:52:32 +02:00
use actix::{Actor, Arbiter, AsyncContext, Context, Handler, Message, Response};
2017-12-28 21:38:37 +01:00
2018-08-09 20:52:32 +02:00
use super::server::{Connections, ServiceHandler};
use super::Token;
2017-12-28 21:38:37 +01:00
#[derive(Message)]
pub(crate) struct Conn<T> {
pub io: T,
2018-08-09 20:52:32 +02:00
pub handler: Token,
2018-08-04 01:09:46 +02:00
pub token: Token,
2017-12-28 21:38:37 +01:00
pub peer: Option<net::SocketAddr>,
}
2018-08-04 01:09:46 +02:00
pub(crate) struct Socket {
pub lst: net::TcpListener,
pub addr: net::SocketAddr,
2018-08-04 01:09:46 +02:00
pub token: Token,
}
2018-08-03 08:17:10 +02:00
#[derive(Clone)]
pub(crate) struct WorkerClient {
pub idx: usize,
tx: UnboundedSender<Conn<net::TcpStream>>,
2018-08-09 20:52:32 +02:00
conns: Connections,
2018-08-03 08:17:10 +02:00
}
impl WorkerClient {
2018-08-09 20:52:32 +02:00
pub fn new(
idx: usize, tx: UnboundedSender<Conn<net::TcpStream>>, conns: Connections,
) -> Self {
WorkerClient { idx, tx, conns }
2018-08-03 08:17:10 +02:00
}
pub fn send(
&self, msg: Conn<net::TcpStream>,
) -> Result<(), SendError<Conn<net::TcpStream>>> {
self.tx.unbounded_send(msg)
}
2018-08-09 20:52:32 +02:00
pub fn available(&self) -> bool {
self.conns.available()
2018-08-03 08:17:10 +02:00
}
}
2017-12-29 01:25:47 +01:00
/// Stop worker message. Returns `true` on successful shutdown
/// and `false` if some connections still alive.
2017-12-28 22:07:29 +01:00
pub(crate) struct StopWorker {
pub graceful: Option<time::Duration>,
}
2018-02-12 21:17:30 +01:00
impl Message for StopWorker {
type Result = Result<bool, ()>;
}
2017-12-28 21:38:37 +01:00
/// Http worker
///
2018-04-14 01:02:01 +02:00
/// Worker accepts Socket objects via unbounded channel and start requests
/// processing.
2018-08-04 01:09:46 +02:00
pub(crate) struct Worker {
2018-08-09 20:52:32 +02:00
conns: Connections,
handlers: Vec<Box<ServiceHandler>>,
2017-12-28 21:38:37 +01:00
}
2018-08-04 01:09:46 +02:00
impl Actor for Worker {
type Context = Context<Self>;
}
2017-12-28 21:38:37 +01:00
2018-08-04 01:09:46 +02:00
impl Worker {
2018-08-09 20:52:32 +02:00
pub(crate) fn new(conns: Connections, handlers: Vec<Box<ServiceHandler>>) -> Self {
Worker { conns, handlers }
}
fn shutdown(&self, force: bool) {
self.handlers.iter().for_each(|h| h.shutdown(force));
2017-12-28 21:38:37 +01:00
}
2017-12-29 01:25:47 +01:00
2018-04-14 01:02:01 +02:00
fn shutdown_timeout(
2018-08-04 01:09:46 +02:00
&self, ctx: &mut Context<Worker>, tx: oneshot::Sender<bool>, dur: time::Duration,
2018-04-14 01:02:01 +02:00
) {
2017-12-29 01:25:47 +01:00
// sleep for 1 second and then check again
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
2018-08-09 20:52:32 +02:00
let num = slf.conns.num_connections();
2017-12-29 01:25:47 +01:00
if num == 0 {
let _ = tx.send(true);
2018-06-14 08:37:19 +02:00
Arbiter::current().do_send(StopArbiter(0));
2017-12-29 01:25:47 +01:00
} else if let Some(d) = dur.checked_sub(time::Duration::new(1, 0)) {
slf.shutdown_timeout(ctx, tx, d);
} else {
info!("Force shutdown http worker, {} connections", num);
2018-08-09 20:52:32 +02:00
slf.shutdown(true);
2017-12-29 01:25:47 +01:00
let _ = tx.send(false);
2018-06-14 08:37:19 +02:00
Arbiter::current().do_send(StopArbiter(0));
2017-12-29 01:25:47 +01:00
}
});
}
2017-12-28 21:38:37 +01:00
}
2018-08-04 01:09:46 +02:00
impl Handler<Conn<net::TcpStream>> for Worker {
2018-01-05 22:30:21 +01:00
type Result = ();
2018-04-14 01:02:01 +02:00
fn handle(&mut self, msg: Conn<net::TcpStream>, _: &mut Context<Self>) {
2018-08-09 20:52:32 +02:00
self.handlers[msg.handler.0].handle(msg.token, msg.io, msg.peer)
2017-12-28 21:38:37 +01:00
}
}
2017-12-28 22:07:29 +01:00
/// `StopWorker` message handler
2018-08-04 01:09:46 +02:00
impl Handler<StopWorker> for Worker {
2018-02-12 21:17:30 +01:00
type Result = Response<bool, ()>;
2018-01-05 22:30:21 +01:00
fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Self::Result {
2018-08-09 20:52:32 +02:00
let num = self.conns.num_connections();
2017-12-29 01:25:47 +01:00
if num == 0 {
info!("Shutting down http worker, 0 connections");
2018-02-01 10:08:08 +01:00
Response::reply(Ok(true))
2017-12-29 01:25:47 +01:00
} else if let Some(dur) = msg.graceful {
2018-08-09 20:52:32 +02:00
self.shutdown(false);
2017-12-29 01:25:47 +01:00
let (tx, rx) = oneshot::channel();
2018-08-09 20:52:32 +02:00
let num = self.conns.num_connections();
if num != 0 {
info!("Graceful http worker shutdown, {} connections", num);
self.shutdown_timeout(ctx, tx, dur);
Response::reply(Ok(true))
} else {
Response::async(rx.map_err(|_| ()))
}
2017-12-29 01:25:47 +01:00
} else {
info!("Force shutdown http worker, {} connections", num);
2018-08-09 20:52:32 +02:00
self.shutdown(true);
2018-02-01 10:08:08 +01:00
Response::reply(Ok(false))
2017-12-29 01:25:47 +01:00
}
2017-12-28 22:07:29 +01:00
}
}