mirror of
https://github.com/fafhrd91/actix-net
synced 2024-11-24 01:11:07 +01:00
fix worker shutdown
This commit is contained in:
parent
ac70f06c4f
commit
2cbcc21168
@ -1,4 +1,5 @@
|
|||||||
//! simple composite service
|
//! simple composite service
|
||||||
|
//! build: cargo run --example basic --features "ssl"
|
||||||
//! to test: curl https://127.0.0.1:8443/ -k
|
//! to test: curl https://127.0.0.1:8443/ -k
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
extern crate actix_net;
|
extern crate actix_net;
|
||||||
|
@ -432,10 +432,6 @@ impl Connections {
|
|||||||
self.0.available()
|
self.0.available()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn num_connections(&self) -> usize {
|
|
||||||
self.0.conn.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report opened connection
|
/// Report opened connection
|
||||||
pub fn connection(&self) -> ConnectionTag {
|
pub fn connection(&self) -> ConnectionTag {
|
||||||
ConnectionTag::new(self.0.clone())
|
ConnectionTag::new(self.0.clone())
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
use std::{fmt, io, net};
|
use std::{fmt, io, net};
|
||||||
|
|
||||||
use futures::{future, Future, Poll};
|
use futures::{future, Future, Poll};
|
||||||
@ -16,6 +20,7 @@ pub(crate) type BoxedServerService = Box<
|
|||||||
|
|
||||||
pub(crate) struct ServerService<T> {
|
pub(crate) struct ServerService<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
|
counter: Arc<AtomicUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Service for ServerService<T>
|
impl<T> Service for ServerService<T>
|
||||||
@ -39,7 +44,11 @@ where
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(stream) = stream {
|
if let Ok(stream) = stream {
|
||||||
Box::new(self.inner.call(stream).map_err(|_| ()))
|
let counter = self.counter.clone();
|
||||||
|
let _ = counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
Box::new(self.inner.call(stream).map_err(|_| ()).map(move |_| {
|
||||||
|
let _ = counter.fetch_sub(1, Ordering::Relaxed);
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
Box::new(future::err(()))
|
Box::new(future::err(()))
|
||||||
}
|
}
|
||||||
@ -48,6 +57,7 @@ where
|
|||||||
|
|
||||||
pub(crate) struct ServerNewService<T> {
|
pub(crate) struct ServerNewService<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
|
counter: Arc<AtomicUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ServerNewService<T>
|
impl<T> ServerNewService<T>
|
||||||
@ -61,11 +71,16 @@ where
|
|||||||
T::Error: fmt::Display,
|
T::Error: fmt::Display,
|
||||||
{
|
{
|
||||||
pub(crate) fn create(inner: T) -> Box<ServerServiceFactory + Send> {
|
pub(crate) fn create(inner: T) -> Box<ServerServiceFactory + Send> {
|
||||||
Box::new(Self { inner })
|
Box::new(Self {
|
||||||
|
inner,
|
||||||
|
counter: Arc::new(AtomicUsize::new(0)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ServerServiceFactory {
|
pub trait ServerServiceFactory {
|
||||||
|
fn counter(&self) -> Arc<AtomicUsize>;
|
||||||
|
|
||||||
fn clone_factory(&self) -> Box<ServerServiceFactory + Send>;
|
fn clone_factory(&self) -> Box<ServerServiceFactory + Send>;
|
||||||
|
|
||||||
fn create(&self) -> Box<Future<Item = BoxedServerService, Error = ()>>;
|
fn create(&self) -> Box<Future<Item = BoxedServerService, Error = ()>>;
|
||||||
@ -81,21 +96,31 @@ where
|
|||||||
T::Future: 'static,
|
T::Future: 'static,
|
||||||
T::Error: fmt::Display,
|
T::Error: fmt::Display,
|
||||||
{
|
{
|
||||||
|
fn counter(&self) -> Arc<AtomicUsize> {
|
||||||
|
self.counter.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn clone_factory(&self) -> Box<ServerServiceFactory + Send> {
|
fn clone_factory(&self) -> Box<ServerServiceFactory + Send> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
|
counter: Arc::new(AtomicUsize::new(0)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(&self) -> Box<Future<Item = BoxedServerService, Error = ()>> {
|
fn create(&self) -> Box<Future<Item = BoxedServerService, Error = ()>> {
|
||||||
Box::new(self.inner.new_service().map_err(|_| ()).map(|inner| {
|
let counter = self.counter.clone();
|
||||||
let service: BoxedServerService = Box::new(ServerService { inner });
|
Box::new(self.inner.new_service().map_err(|_| ()).map(move |inner| {
|
||||||
|
let service: BoxedServerService = Box::new(ServerService { inner, counter });
|
||||||
service
|
service
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerServiceFactory for Box<ServerServiceFactory> {
|
impl ServerServiceFactory for Box<ServerServiceFactory> {
|
||||||
|
fn counter(&self) -> Arc<AtomicUsize> {
|
||||||
|
self.as_ref().counter()
|
||||||
|
}
|
||||||
|
|
||||||
fn clone_factory(&self) -> Box<ServerServiceFactory + Send> {
|
fn clone_factory(&self) -> Box<ServerServiceFactory + Send> {
|
||||||
self.as_ref().clone_factory()
|
self.as_ref().clone_factory()
|
||||||
}
|
}
|
||||||
|
@ -583,7 +583,7 @@ where
|
|||||||
type Future = MapErrFuture<A, F, E>;
|
type Future = MapErrFuture<A, F, E>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.a.poll_ready().map_err(|e| (self.f)(e))
|
self.a.poll_ready().map_err(&self.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
@ -619,7 +619,7 @@ where
|
|||||||
type Error = E;
|
type Error = E;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
self.fut.poll().map_err(|e| (self.f)(e))
|
self.fut.poll().map_err(&self.f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,6 +795,6 @@ where
|
|||||||
type Error = E;
|
type Error = E;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
self.fut.poll().map_err(|e| (self.f)(e))
|
self.fut.poll().map_err(&self.f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use futures::{future, future::FutureResult, Async, Future, Poll};
|
|||||||
use openssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
use openssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream};
|
use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream};
|
||||||
use tokio_tcp::TcpStream;
|
|
||||||
use tower_service::{NewService, Service};
|
use tower_service::{NewService, Service};
|
||||||
|
|
||||||
use {IntoNewService, IoStream};
|
use {IntoNewService, IoStream};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::{net, time};
|
use std::{net, time};
|
||||||
|
|
||||||
use futures::future;
|
|
||||||
use futures::sync::mpsc::{SendError, UnboundedSender};
|
use futures::sync::mpsc::{SendError, UnboundedSender};
|
||||||
use futures::sync::oneshot;
|
use futures::sync::oneshot;
|
||||||
|
use futures::{future, Future};
|
||||||
|
|
||||||
use actix::msgs::StopArbiter;
|
use actix::msgs::StopArbiter;
|
||||||
use actix::{
|
use actix::{
|
||||||
@ -59,6 +61,7 @@ impl Message for StopWorker {
|
|||||||
pub(crate) struct Worker {
|
pub(crate) struct Worker {
|
||||||
// conns: Connections,
|
// conns: Connections,
|
||||||
services: Vec<BoxedServerService>,
|
services: Vec<BoxedServerService>,
|
||||||
|
counters: Vec<Arc<AtomicUsize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for Worker {
|
impl Actor for Worker {
|
||||||
@ -71,6 +74,7 @@ impl Worker {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let wrk = Worker {
|
let wrk = Worker {
|
||||||
services: Vec::new(),
|
services: Vec::new(),
|
||||||
|
counters: services.iter().map(|i| i.counter()).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.wait(
|
ctx.wait(
|
||||||
@ -94,23 +98,26 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown_timeout(
|
fn shutdown_timeout(
|
||||||
&self, _ctx: &mut Context<Worker>, _tx: oneshot::Sender<bool>, _dur: time::Duration,
|
&self, ctx: &mut Context<Worker>, tx: oneshot::Sender<bool>, dur: time::Duration,
|
||||||
) {
|
) {
|
||||||
// sleep for 1 second and then check again
|
// sleep for 1 second and then check again
|
||||||
// ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
||||||
// let num = slf.conns.num_connections();
|
let num = slf
|
||||||
// if num == 0 {
|
.counters
|
||||||
// let _ = tx.send(true);
|
.iter()
|
||||||
// Arbiter::current().do_send(StopArbiter(0));
|
.fold(0, |i, v| i + v.load(Ordering::Relaxed));
|
||||||
// } else if let Some(d) = dur.checked_sub(time::Duration::new(1, 0)) {
|
if num == 0 {
|
||||||
// slf.shutdown_timeout(ctx, tx, d);
|
let _ = tx.send(true);
|
||||||
// } else {
|
Arbiter::current().do_send(StopArbiter(0));
|
||||||
// info!("Force shutdown http worker, {} connections", num);
|
} else if let Some(d) = dur.checked_sub(time::Duration::new(1, 0)) {
|
||||||
// slf.shutdown(true);
|
slf.shutdown_timeout(ctx, tx, d);
|
||||||
// let _ = tx.send(false);
|
} else {
|
||||||
// Arbiter::current().do_send(StopArbiter(0));
|
info!("Force shutdown http worker, {} connections", num);
|
||||||
// }
|
slf.shutdown(true);
|
||||||
// });
|
let _ = tx.send(false);
|
||||||
|
Arbiter::current().do_send(StopArbiter(0));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,27 +133,32 @@ impl Handler<Conn> for Worker {
|
|||||||
impl Handler<StopWorker> for Worker {
|
impl Handler<StopWorker> for Worker {
|
||||||
type Result = Response<bool, ()>;
|
type Result = Response<bool, ()>;
|
||||||
|
|
||||||
fn handle(&mut self, _msg: StopWorker, _ctx: &mut Context<Self>) -> Self::Result {
|
fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Self::Result {
|
||||||
unimplemented!()
|
let num = self
|
||||||
// let num = self.conns.num_connections();
|
.counters
|
||||||
// if num == 0 {
|
.iter()
|
||||||
// info!("Shutting down http worker, 0 connections");
|
.fold(0, |i, v| i + v.load(Ordering::Relaxed));
|
||||||
// Response::reply(Ok(true))
|
if num == 0 {
|
||||||
// } else if let Some(dur) = msg.graceful {
|
info!("Shutting down http worker, 0 connections");
|
||||||
// self.shutdown(false);
|
Response::reply(Ok(true))
|
||||||
// let (tx, rx) = oneshot::channel();
|
} else if let Some(dur) = msg.graceful {
|
||||||
// let num = self.conns.num_connections();
|
self.shutdown(false);
|
||||||
// if num != 0 {
|
let (tx, rx) = oneshot::channel();
|
||||||
// info!("Graceful http worker shutdown, {} connections", num);
|
let num = self
|
||||||
// self.shutdown_timeout(ctx, tx, dur);
|
.counters
|
||||||
// Response::reply(Ok(true))
|
.iter()
|
||||||
// } else {
|
.fold(0, |i, v| i + v.load(Ordering::Relaxed));
|
||||||
// Response::async(rx.map_err(|_| ()))
|
if num != 0 {
|
||||||
// }
|
info!("Graceful http worker shutdown, {} connections", num);
|
||||||
// } else {
|
self.shutdown_timeout(ctx, tx, dur);
|
||||||
// info!("Force shutdown http worker, {} connections", num);
|
Response::reply(Ok(true))
|
||||||
// self.shutdown(true);
|
} else {
|
||||||
// Response::reply(Ok(false))
|
Response::async(rx.map_err(|_| ()))
|
||||||
// }
|
}
|
||||||
|
} else {
|
||||||
|
info!("Force shutdown http worker, {} connections", num);
|
||||||
|
self.shutdown(true);
|
||||||
|
Response::reply(Ok(false))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user