2019-04-08 10:21:29 +00:00
|
|
|
use failure::*;
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use std::sync::Mutex;
|
|
|
|
|
|
|
|
use futures::*;
|
|
|
|
|
2019-09-02 11:04:44 +00:00
|
|
|
use tokio_net::signal::unix::{signal, SignalKind};
|
2019-04-08 10:21:29 +00:00
|
|
|
|
2019-04-30 08:21:48 +00:00
|
|
|
use crate::tools::{self, BroadcastData};
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
|
|
|
pub enum ServerMode {
|
|
|
|
Normal,
|
|
|
|
Shutdown,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ServerState {
|
|
|
|
pub mode: ServerMode,
|
2019-04-30 08:21:48 +00:00
|
|
|
pub shutdown_listeners: BroadcastData<()>,
|
|
|
|
pub last_worker_listeners: BroadcastData<()>,
|
2019-04-08 10:21:29 +00:00
|
|
|
pub worker_count: usize,
|
|
|
|
pub reload_request: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref SERVER_STATE: Mutex<ServerState> = Mutex::new(ServerState {
|
|
|
|
mode: ServerMode::Normal,
|
2019-04-30 08:21:48 +00:00
|
|
|
shutdown_listeners: BroadcastData::new(),
|
|
|
|
last_worker_listeners: BroadcastData::new(),
|
2019-04-08 10:21:29 +00:00
|
|
|
worker_count: 0,
|
|
|
|
reload_request: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn server_state_init() -> Result<(), Error> {
|
|
|
|
|
2019-09-02 11:04:44 +00:00
|
|
|
let stream = signal(SignalKind::interrupt())?;
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
let future = stream.for_each(|_| {
|
|
|
|
println!("got shutdown request (SIGINT)");
|
|
|
|
SERVER_STATE.lock().unwrap().reload_request = false;
|
|
|
|
tools::request_shutdown();
|
2019-08-23 11:41:38 +00:00
|
|
|
futures::future::ready(())
|
|
|
|
});
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
let abort_future = last_worker_future().map_err(|_| {});
|
2019-08-23 11:41:38 +00:00
|
|
|
let task = futures::future::select(future, abort_future);
|
2019-04-08 10:21:29 +00:00
|
|
|
|
2019-08-23 11:41:38 +00:00
|
|
|
tokio::spawn(task.map(|_| ()));
|
2019-04-08 10:21:29 +00:00
|
|
|
|
2019-09-02 11:04:44 +00:00
|
|
|
let stream = signal(SignalKind::hangup())?;
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
let future = stream.for_each(|_| {
|
|
|
|
println!("got reload request (SIGHUP)");
|
|
|
|
SERVER_STATE.lock().unwrap().reload_request = true;
|
|
|
|
tools::request_shutdown();
|
2019-08-23 11:41:38 +00:00
|
|
|
futures::future::ready(())
|
|
|
|
});
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
let abort_future = last_worker_future().map_err(|_| {});
|
2019-08-23 11:41:38 +00:00
|
|
|
let task = futures::future::select(future, abort_future);
|
2019-04-08 10:21:29 +00:00
|
|
|
|
2019-08-23 11:41:38 +00:00
|
|
|
tokio::spawn(task.map(|_| ()));
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_reload_request() -> bool {
|
|
|
|
let data = SERVER_STATE.lock().unwrap();
|
|
|
|
|
2019-10-26 09:36:01 +00:00
|
|
|
data.mode == ServerMode::Shutdown && data.reload_request
|
2019-04-08 10:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn server_shutdown() {
|
|
|
|
let mut data = SERVER_STATE.lock().unwrap();
|
|
|
|
|
|
|
|
println!("SET SHUTDOWN MODE");
|
|
|
|
|
|
|
|
data.mode = ServerMode::Shutdown;
|
|
|
|
|
2019-04-30 08:21:48 +00:00
|
|
|
data.shutdown_listeners.notify_listeners(Ok(()));
|
2019-04-08 10:21:29 +00:00
|
|
|
|
|
|
|
drop(data); // unlock
|
|
|
|
|
|
|
|
check_last_worker();
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:41:38 +00:00
|
|
|
pub fn shutdown_future() -> impl Future<Output = ()> {
|
2019-04-08 10:21:29 +00:00
|
|
|
let mut data = SERVER_STATE.lock().unwrap();
|
2019-08-23 11:41:38 +00:00
|
|
|
data
|
|
|
|
.shutdown_listeners
|
|
|
|
.listen()
|
|
|
|
.map(|_| ())
|
2019-04-08 10:21:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-23 11:41:38 +00:00
|
|
|
pub fn last_worker_future() -> impl Future<Output = Result<(), Error>> {
|
2019-04-08 10:21:29 +00:00
|
|
|
let mut data = SERVER_STATE.lock().unwrap();
|
2019-04-30 08:21:48 +00:00
|
|
|
data.last_worker_listeners.listen()
|
2019-04-08 10:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_worker_count(count: usize) {
|
|
|
|
let mut data = SERVER_STATE.lock().unwrap();
|
|
|
|
data.worker_count = count;
|
|
|
|
|
|
|
|
if !(data.mode == ServerMode::Shutdown && data.worker_count == 0) { return; }
|
|
|
|
|
2019-04-30 08:21:48 +00:00
|
|
|
data.last_worker_listeners.notify_listeners(Ok(()));
|
2019-04-08 10:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn check_last_worker() {
|
|
|
|
|
|
|
|
let mut data = SERVER_STATE.lock().unwrap();
|
|
|
|
|
|
|
|
if !(data.mode == ServerMode::Shutdown && data.worker_count == 0) { return; }
|
|
|
|
|
2019-04-30 08:21:48 +00:00
|
|
|
data.last_worker_listeners.notify_listeners(Ok(()));
|
2019-04-08 10:21:29 +00:00
|
|
|
}
|