♻️ Graceful shutdown is now a oneshot for both relays and servers
parent
26b4c335c6
commit
e9d335eec1
|
@ -20,6 +20,6 @@ pub fn load <
|
|||
|
||||
{
|
||||
let config_s = String::from_utf8 (buffer).unwrap_or_else (|_| panic! ("Can't parse {:?} as UTF-8", config_file_path));
|
||||
toml::from_str (&config_s).unwrap_or_else (|_| panic! ("Can't parse {:?} as TOML", config_file_path))
|
||||
toml::from_str (&config_s).unwrap_or_else (|e| panic! ("Can't parse {:?} as TOML: {}", config_file_path, e))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fs::File,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use structopt::StructOpt;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
mod load_toml;
|
||||
|
||||
|
@ -15,10 +16,33 @@ struct Opt {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main () -> Result <(), Box <dyn Error>> {
|
||||
tracing_subscriber::fmt::init ();
|
||||
|
||||
let config_file = load_toml::load ("config/ptth_server.toml");
|
||||
|
||||
let rx = {
|
||||
let (tx, rx) = oneshot::channel::<()> ();
|
||||
|
||||
// I have to put the tx into a Cell here so that if Ctrl-C gets
|
||||
// called multiple times, we won't send multiple shutdowns to the
|
||||
// oneshot channel. (Which would be a compile error)
|
||||
|
||||
let tx = Some (tx);
|
||||
let tx = std::cell::Cell::new (tx);
|
||||
|
||||
ctrlc::set_handler (move ||{
|
||||
let tx = tx.replace (None);
|
||||
|
||||
if let Some (tx) = tx {
|
||||
tx.send (()).unwrap ();
|
||||
}
|
||||
}).expect ("Error setting Ctrl-C handler");
|
||||
|
||||
rx
|
||||
};
|
||||
|
||||
ptth::server::run_server (
|
||||
config_file,
|
||||
None
|
||||
rx
|
||||
).await
|
||||
}
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -43,10 +43,6 @@ mod tests {
|
|||
use std::{
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{
|
||||
AtomicBool,
|
||||
Ordering,
|
||||
},
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
@ -91,6 +87,10 @@ mod tests {
|
|||
use reqwest::Client;
|
||||
use tracing::{info};
|
||||
|
||||
// This should be the first line of the `tracing`
|
||||
// crate documentation. Their docs are awful, but you
|
||||
// didn't hear it from me.
|
||||
|
||||
tracing_subscriber::fmt::init ();
|
||||
|
||||
let mut rt = Runtime::new ().unwrap ();
|
||||
|
@ -126,11 +126,11 @@ mod tests {
|
|||
relay_url: "http://127.0.0.1:4000/7ZSFUKGV".into (),
|
||||
file_server_root: None,
|
||||
};
|
||||
let stop_server_atomic = Arc::new (AtomicBool::from (false));
|
||||
|
||||
let (stop_server_tx, stop_server_rx) = oneshot::channel ();
|
||||
let task_server = {
|
||||
let stop_server_atomic = stop_server_atomic.clone ();
|
||||
spawn (async move {
|
||||
server::run_server (config_file, Some (stop_server_atomic)).await.unwrap ();
|
||||
server::run_server (config_file, stop_server_rx).await.unwrap ();
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -176,7 +176,7 @@ mod tests {
|
|||
|
||||
info! ("Shutting down end-to-end test");
|
||||
|
||||
stop_server_atomic.store (true, Ordering::Relaxed);
|
||||
stop_server_tx.send (()).unwrap ();
|
||||
stop_relay_tx.send (()).unwrap ();
|
||||
|
||||
info! ("Sent stop messages");
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::FutureExt;
|
||||
use handlebars::Handlebars;
|
||||
use hyper::{
|
||||
StatusCode,
|
||||
|
@ -12,8 +13,10 @@ use hyper::{
|
|||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
use tokio::{
|
||||
sync::oneshot,
|
||||
time::delay_for,
|
||||
};
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
http_serde,
|
||||
|
@ -108,16 +111,9 @@ pub struct Config {
|
|||
pub file_server_root: Option <PathBuf>,
|
||||
}
|
||||
|
||||
use std::sync::atomic::{
|
||||
AtomicBool,
|
||||
Ordering,
|
||||
};
|
||||
|
||||
use tracing::info;
|
||||
|
||||
pub async fn run_server (
|
||||
config_file: ConfigFile,
|
||||
shutdown_atomic: Option <Arc <AtomicBool>>
|
||||
shutdown_oneshot: oneshot::Receiver <()>
|
||||
)
|
||||
-> Result <(), Box <dyn Error>>
|
||||
{
|
||||
|
@ -150,31 +146,36 @@ pub async fn run_server (
|
|||
});
|
||||
|
||||
let mut backoff_delay = 0;
|
||||
let mut shutdown_oneshot = shutdown_oneshot.fuse ();
|
||||
|
||||
loop {
|
||||
if let Some (a) = &shutdown_atomic {
|
||||
if a.load (Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if backoff_delay > 0 {
|
||||
delay_for (Duration::from_millis (backoff_delay)).await;
|
||||
}
|
||||
|
||||
if let Some (a) = &shutdown_atomic {
|
||||
if a.load (Ordering::Relaxed) {
|
||||
let mut delay = delay_for (Duration::from_millis (backoff_delay)).fuse ();
|
||||
|
||||
if futures::select! (
|
||||
_ = delay => false,
|
||||
_ = shutdown_oneshot => true,
|
||||
) {
|
||||
info! ("Received graceful shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info! ("http_listen");
|
||||
|
||||
let req_req = state.client.get (&format! ("{}/http_listen/{}", state.config.relay_url, config_file.name));
|
||||
let req_req = state.client.get (&format! ("{}/http_listen/{}", state.config.relay_url, config_file.name)).send ();
|
||||
|
||||
let err_backoff_delay = std::cmp::min (30_000, backoff_delay * 2 + 500);
|
||||
|
||||
let req_resp = match req_req.send ().await {
|
||||
let req_req = futures::select! {
|
||||
r = req_req.fuse () => r,
|
||||
_ = shutdown_oneshot => {
|
||||
info! ("Received graceful shutdown");
|
||||
break;
|
||||
},
|
||||
};
|
||||
|
||||
let req_resp = match req_req {
|
||||
Err (e) => {
|
||||
eprintln! ("Err: {:?}", e);
|
||||
backoff_delay = err_backoff_delay;
|
||||
|
|
Loading…
Reference in New Issue