use std::{borrow::BorrowMut, sync::Arc};
use tokio::sync::broadcast::{Receiver, Sender};
use tokio::sync::Mutex;
#[derive(Debug, Clone)]
pub struct ShutdownHandle {
sender: Sender<()>,
}
impl Default for ShutdownHandle {
fn default() -> Self {
Self::new()
}
}
impl ShutdownHandle {
pub fn new() -> Self {
Self {
sender: tokio::sync::broadcast::channel(1).0,
}
}
pub fn shutdown(&self) {
if let Err(e) = self.sender.send(()) {
log::warn!("Failed to send shutdown signal: {e:?}");
}
}
pub fn new_listener(&self) -> DelegatedShutdownListener {
DelegatedShutdownListener::new(self.sender.subscribe())
}
}
#[derive(Clone, Debug)]
pub struct DelegatedShutdownListener {
receiver: Arc<Mutex<Receiver<()>>>,
}
impl DelegatedShutdownListener {
pub(crate) fn new(receiver: Receiver<()>) -> Self {
Self {
receiver: Arc::new(Mutex::new(receiver)),
}
}
pub fn should_shutdown(&mut self) -> bool {
match self.receiver.try_lock() {
Ok(mut guard) => {
match guard.try_recv() {
Ok(_) => true,
Err(tokio::sync::broadcast::error::TryRecvError::Closed) => true,
Err(_) => false,
}
}
Err(_) => false,
}
}
pub async fn wait_for_shutdown(&mut self) {
self.receiver
.borrow_mut()
.lock()
.await
.recv()
.await
.expect("Failed to receive shutdown signal");
}
}
#[derive(derive_more::Error, derive_more::Display, Debug)]
pub struct ShutdownSignalError {
msg: String,
}
impl Default for ShutdownSignalError {
fn default() -> Self {
Self {
msg: "Execution cancelled by shutdown signal".to_string(),
}
}
}