mirror of
https://github.com/mikedilger/chorus.git
synced 2026-08-01 07:21:39 +00:00
Gracefully shutdown
This commit is contained in:
parent
c6a74b9000
commit
089305b57d
@ -2,8 +2,10 @@ use crate::config::{Config, FriendlyConfig};
|
||||
use crate::store::Store;
|
||||
use hyper::server::conn::Http;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::OnceLock;
|
||||
use tokio::sync::broadcast::Sender;
|
||||
use tokio::sync::broadcast::Sender as BroadcastSender;
|
||||
use tokio::sync::watch::Sender as WatchSender;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub struct Globals {
|
||||
@ -16,7 +18,10 @@ pub struct Globals {
|
||||
/// Every handler needs to listen to it and check if the incoming event matches any
|
||||
/// subscribed fitlers for their client, and if so, send the event to their client under
|
||||
/// that subscription.
|
||||
pub new_events: Sender<usize>,
|
||||
pub new_events: BroadcastSender<usize>,
|
||||
|
||||
pub num_clients: AtomicUsize,
|
||||
pub shutting_down: WatchSender<bool>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -25,14 +30,17 @@ lazy_static! {
|
||||
http_server.http1_only(true);
|
||||
http_server.http1_keep_alive(true);
|
||||
|
||||
let (sender, _) = tokio::sync::broadcast::channel(512);
|
||||
let (new_events, _) = tokio::sync::broadcast::channel(512);
|
||||
let (shutting_down, _) = tokio::sync::watch::channel(false);
|
||||
|
||||
Globals {
|
||||
config: RwLock::new(FriendlyConfig::default().into_config().unwrap()),
|
||||
store: OnceLock::new(),
|
||||
http_server,
|
||||
rid: OnceLock::new(),
|
||||
new_events: sender,
|
||||
new_events,
|
||||
num_clients: AtomicUsize::new(0),
|
||||
shutting_down,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
53
src/main.rs
53
src/main.rs
@ -30,7 +30,9 @@ use std::future::Future;
|
||||
use std::io::Read;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
use textnonce::TextNonce;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
@ -120,6 +122,41 @@ async fn main() -> Result<(), Error> {
|
||||
};
|
||||
}
|
||||
|
||||
// Pre-sync in case something below hangs up
|
||||
let _ = GLOBALS.store.get().unwrap().sync();
|
||||
|
||||
// Set the shutting down signal
|
||||
let _ = GLOBALS.shutting_down.send(true);
|
||||
|
||||
// Wait for active websockets to shutdown gracefully
|
||||
let mut num_clients = GLOBALS.num_clients.load(Ordering::Relaxed);
|
||||
if num_clients != 0 {
|
||||
log::info!("Waiting for {num_clients} websockets to shutdown...");
|
||||
|
||||
// We will check if all clients have shutdown every 25ms
|
||||
let sleep = tokio::time::sleep(Duration::from_millis(25));
|
||||
tokio::pin!(sleep);
|
||||
|
||||
while num_clients != 0 {
|
||||
// If we get another shutdown signal, stop waiting for websockets
|
||||
tokio::select! {
|
||||
v = interrupt_signal.recv() => if v.is_some() {
|
||||
break;
|
||||
},
|
||||
v = quit_signal.recv() => if v.is_some() {
|
||||
break;
|
||||
},
|
||||
v = terminate_signal.recv() => if v.is_some() {
|
||||
break;
|
||||
},
|
||||
() = &mut sleep => {
|
||||
num_clients = GLOBALS.num_clients.load(Ordering::Relaxed);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Syncing and shutting down.");
|
||||
let _ = GLOBALS.store.get().unwrap().sync();
|
||||
|
||||
@ -209,6 +246,9 @@ async fn handle_http_request(
|
||||
user: None,
|
||||
};
|
||||
|
||||
// Increment count of active websockets
|
||||
let _ = GLOBALS.num_clients.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
// Handle the websocket
|
||||
if let Err(e) = ws_service.handle_websocket_stream().await {
|
||||
if matches!(
|
||||
@ -223,6 +263,9 @@ async fn handle_http_request(
|
||||
}
|
||||
}
|
||||
|
||||
// DecrementIncrement count of active websockets
|
||||
let _ = GLOBALS.num_clients.fetch_sub(1, Ordering::SeqCst);
|
||||
|
||||
log::info!("{}: websocket ended", peer);
|
||||
}
|
||||
Err(e) => {
|
||||
@ -263,6 +306,9 @@ impl WebSocketService {
|
||||
}
|
||||
|
||||
async fn handle_websocket_stream(&mut self) -> Result<(), Error> {
|
||||
// Subscribe to the shutting down channel
|
||||
let mut shutting_down = GLOBALS.shutting_down.subscribe();
|
||||
|
||||
// Subscribe to the new_events broadcast channel
|
||||
let mut new_events = GLOBALS.new_events.subscribe();
|
||||
|
||||
@ -278,13 +324,18 @@ impl WebSocketService {
|
||||
let message = message?;
|
||||
self.handle_websocket_message(message).await?;
|
||||
},
|
||||
None => break, // websocket must be closed
|
||||
None => break, // the websocket is closed
|
||||
}
|
||||
},
|
||||
offset_result = new_events.recv() => {
|
||||
let offset = offset_result?;
|
||||
self.handle_new_event(offset).await?;
|
||||
},
|
||||
_r = shutting_down.changed() => {
|
||||
// Shutdown the websocket gracefully
|
||||
self.websocket.send(Message::Close(None)).await?;
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user