mirror of
https://github.com/actix/actix-web.git
synced 2024-12-30 03:50:42 +00:00
separate stop worker channel
This commit is contained in:
parent
60144a3cb8
commit
0e3d1068da
2 changed files with 64 additions and 51 deletions
|
@ -249,15 +249,16 @@ impl Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_worker(&self, idx: usize, notify: AcceptNotify) -> WorkerClient {
|
fn start_worker(&self, idx: usize, notify: AcceptNotify) -> WorkerClient {
|
||||||
let (tx, rx) = unbounded();
|
let (tx1, rx1) = unbounded();
|
||||||
|
let (tx2, rx2) = unbounded();
|
||||||
let timeout = self.shutdown_timeout;
|
let timeout = self.shutdown_timeout;
|
||||||
let avail = WorkerAvailability::new(notify);
|
let avail = WorkerAvailability::new(notify);
|
||||||
let worker = WorkerClient::new(idx, tx, avail.clone());
|
let worker = WorkerClient::new(idx, tx1, tx2, avail.clone());
|
||||||
let services: Vec<Box<InternalServiceFactory>> =
|
let services: Vec<Box<InternalServiceFactory>> =
|
||||||
self.services.iter().map(|v| v.clone_factory()).collect();
|
self.services.iter().map(|v| v.clone_factory()).collect();
|
||||||
|
|
||||||
Arbiter::new(format!("actix-net-worker-{}", idx)).do_send(Execute::new(move || {
|
Arbiter::new(format!("actix-net-worker-{}", idx)).do_send(Execute::new(move || {
|
||||||
Worker::start(rx, services, avail, timeout.clone());
|
Worker::start(rx1, rx2, services, avail, timeout.clone());
|
||||||
Ok::<_, ()>(())
|
Ok::<_, ()>(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -317,6 +318,7 @@ impl Handler<StopServer> for Server {
|
||||||
type Result = Response<(), ()>;
|
type Result = Response<(), ()>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: StopServer, ctx: &mut Context<Self>) -> Self::Result {
|
fn handle(&mut self, msg: StopServer, ctx: &mut Context<Self>) -> Self::Result {
|
||||||
|
println!("STOP command");
|
||||||
// stop accept thread
|
// stop accept thread
|
||||||
self.accept.send(Command::Stop);
|
self.accept.send(Command::Stop);
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,13 @@ use super::services::{BoxedServerService, InternalServiceFactory, ServerMessage}
|
||||||
use super::Token;
|
use super::Token;
|
||||||
use counter::Counter;
|
use counter::Counter;
|
||||||
|
|
||||||
pub(crate) enum WorkerCommand {
|
pub(crate) struct WorkerCommand(Conn);
|
||||||
Message(Conn),
|
|
||||||
/// Stop worker message. Returns `true` on successful shutdown
|
/// Stop worker message. Returns `true` on successful shutdown
|
||||||
/// and `false` if some connections still alive.
|
/// and `false` if some connections still alive.
|
||||||
Stop(bool, oneshot::Sender<bool>),
|
pub(crate) struct StopCommand {
|
||||||
|
graceful: bool,
|
||||||
|
result: oneshot::Sender<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Message)]
|
#[derive(Debug, Message)]
|
||||||
|
@ -55,26 +57,30 @@ thread_local! {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct WorkerClient {
|
pub(crate) struct WorkerClient {
|
||||||
pub idx: usize,
|
pub idx: usize,
|
||||||
tx: UnboundedSender<WorkerCommand>,
|
tx1: UnboundedSender<WorkerCommand>,
|
||||||
|
tx2: UnboundedSender<StopCommand>,
|
||||||
avail: WorkerAvailability,
|
avail: WorkerAvailability,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerClient {
|
impl WorkerClient {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
idx: usize,
|
idx: usize,
|
||||||
tx: UnboundedSender<WorkerCommand>,
|
tx1: UnboundedSender<WorkerCommand>,
|
||||||
|
tx2: UnboundedSender<StopCommand>,
|
||||||
avail: WorkerAvailability,
|
avail: WorkerAvailability,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
WorkerClient { idx, tx, avail }
|
WorkerClient {
|
||||||
|
idx,
|
||||||
|
tx1,
|
||||||
|
tx2,
|
||||||
|
avail,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, msg: Conn) -> Result<(), Conn> {
|
pub fn send(&self, msg: Conn) -> Result<(), Conn> {
|
||||||
self.tx
|
self.tx1
|
||||||
.unbounded_send(WorkerCommand::Message(msg))
|
.unbounded_send(WorkerCommand(msg))
|
||||||
.map_err(|e| match e.into_inner() {
|
.map_err(|msg| msg.into_inner().0)
|
||||||
WorkerCommand::Message(msg) => msg,
|
|
||||||
_ => panic!(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available(&self) -> bool {
|
pub fn available(&self) -> bool {
|
||||||
|
@ -82,8 +88,8 @@ impl WorkerClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(&self, graceful: bool) -> oneshot::Receiver<bool> {
|
pub fn stop(&self, graceful: bool) -> oneshot::Receiver<bool> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (result, rx) = oneshot::channel();
|
||||||
let _ = self.tx.unbounded_send(WorkerCommand::Stop(graceful, tx));
|
let _ = self.tx2.unbounded_send(StopCommand { graceful, result });
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +126,7 @@ impl WorkerAvailability {
|
||||||
/// processing.
|
/// processing.
|
||||||
pub(crate) struct Worker {
|
pub(crate) struct Worker {
|
||||||
rx: UnboundedReceiver<WorkerCommand>,
|
rx: UnboundedReceiver<WorkerCommand>,
|
||||||
|
rx2: UnboundedReceiver<StopCommand>,
|
||||||
services: Vec<BoxedServerService>,
|
services: Vec<BoxedServerService>,
|
||||||
availability: WorkerAvailability,
|
availability: WorkerAvailability,
|
||||||
conns: Counter,
|
conns: Counter,
|
||||||
|
@ -131,6 +138,7 @@ pub(crate) struct Worker {
|
||||||
impl Worker {
|
impl Worker {
|
||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
rx: UnboundedReceiver<WorkerCommand>,
|
rx: UnboundedReceiver<WorkerCommand>,
|
||||||
|
rx2: UnboundedReceiver<StopCommand>,
|
||||||
factories: Vec<Box<InternalServiceFactory>>,
|
factories: Vec<Box<InternalServiceFactory>>,
|
||||||
availability: WorkerAvailability,
|
availability: WorkerAvailability,
|
||||||
shutdown_timeout: time::Duration,
|
shutdown_timeout: time::Duration,
|
||||||
|
@ -138,6 +146,7 @@ impl Worker {
|
||||||
availability.set(false);
|
availability.set(false);
|
||||||
let mut wrk = MAX_CONNS_COUNTER.with(|conns| Worker {
|
let mut wrk = MAX_CONNS_COUNTER.with(|conns| Worker {
|
||||||
rx,
|
rx,
|
||||||
|
rx2,
|
||||||
availability,
|
availability,
|
||||||
factories,
|
factories,
|
||||||
shutdown_timeout,
|
shutdown_timeout,
|
||||||
|
@ -216,6 +225,39 @@ impl Future for Worker {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
// `StopWorker` message handler
|
||||||
|
match self.rx2.poll() {
|
||||||
|
Ok(Async::Ready(Some(StopCommand { graceful, result }))) => {
|
||||||
|
self.availability.set(false);
|
||||||
|
let num = num_connections();
|
||||||
|
if num == 0 {
|
||||||
|
info!("Shutting down worker, 0 connections");
|
||||||
|
let _ = result.send(true);
|
||||||
|
return Ok(Async::Ready(()));
|
||||||
|
} else if graceful {
|
||||||
|
self.shutdown(false);
|
||||||
|
let num = num_connections();
|
||||||
|
if num != 0 {
|
||||||
|
info!("Graceful worker shutdown, {} connections", num);
|
||||||
|
self.state = WorkerState::Shutdown(
|
||||||
|
sleep(time::Duration::from_secs(1)),
|
||||||
|
sleep(self.shutdown_timeout),
|
||||||
|
result,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = result.send(true);
|
||||||
|
return Ok(Async::Ready(()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("Force shutdown worker, {} connections", num);
|
||||||
|
self.shutdown(true);
|
||||||
|
let _ = result.send(false);
|
||||||
|
return Ok(Async::Ready(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
let state = mem::replace(&mut self.state, WorkerState::None);
|
let state = mem::replace(&mut self.state, WorkerState::None);
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
|
@ -321,7 +363,7 @@ impl Future for Worker {
|
||||||
loop {
|
loop {
|
||||||
match self.rx.poll() {
|
match self.rx.poll() {
|
||||||
// handle incoming tcp stream
|
// handle incoming tcp stream
|
||||||
Ok(Async::Ready(Some(WorkerCommand::Message(msg)))) => {
|
Ok(Async::Ready(Some(WorkerCommand(msg)))) => {
|
||||||
match self.check_readiness(false) {
|
match self.check_readiness(false) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let guard = self.conns.get();
|
let guard = self.conns.get();
|
||||||
|
@ -348,35 +390,6 @@ impl Future for Worker {
|
||||||
}
|
}
|
||||||
return self.poll();
|
return self.poll();
|
||||||
}
|
}
|
||||||
// `StopWorker` message handler
|
|
||||||
Ok(Async::Ready(Some(WorkerCommand::Stop(graceful, tx)))) => {
|
|
||||||
self.availability.set(false);
|
|
||||||
let num = num_connections();
|
|
||||||
if num == 0 {
|
|
||||||
info!("Shutting down worker, 0 connections");
|
|
||||||
let _ = tx.send(true);
|
|
||||||
return Ok(Async::Ready(()));
|
|
||||||
} else if graceful {
|
|
||||||
self.shutdown(false);
|
|
||||||
let num = num_connections();
|
|
||||||
if num != 0 {
|
|
||||||
info!("Graceful worker shutdown, {} connections", num);
|
|
||||||
break Some(WorkerState::Shutdown(
|
|
||||||
sleep(time::Duration::from_secs(1)),
|
|
||||||
sleep(self.shutdown_timeout),
|
|
||||||
tx,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
let _ = tx.send(true);
|
|
||||||
return Ok(Async::Ready(()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
info!("Force shutdown worker, {} connections", num);
|
|
||||||
self.shutdown(true);
|
|
||||||
let _ = tx.send(false);
|
|
||||||
return Ok(Async::Ready(()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
self.state = WorkerState::Available;
|
self.state = WorkerState::Available;
|
||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
|
@ -387,7 +400,5 @@ impl Future for Worker {
|
||||||
}
|
}
|
||||||
WorkerState::None => panic!(),
|
WorkerState::None => panic!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Async::NotReady)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue