use std::future::Future;
use std::pin::pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use futures::future::{select, Either};
use tokio::signal::unix::{signal, SignalKind};
pub async fn waiting_sigterm<Fut, R>(future: Fut) -> Either<R, Fut>
where
Fut: Future<Output = R> + Unpin,
{
waiting_sigterm_flag(future, Arc::new(AtomicBool::new(false)), 0).await
}
async fn waiting_sigterm_flag<Fut, R>(future: Fut, signal_flag: Arc<AtomicBool>, grace_millis: u64) -> Either<R, Fut>
where
Fut: Future<Output = R> + Unpin,
{
let mut signal = signal(SignalKind::terminate()).unwrap();
let future = match select(pin!(signal.recv()), future).await {
Either::Left((_, future)) => future,
Either::Right((r, _)) => return Either::Left(r), };
if grace_millis == 0 {
return Either::Right(future);
}
signal_flag.store(true, Ordering::SeqCst);
match select(pin!(tokio::time::sleep(Duration::from_millis(grace_millis))), future).await {
Either::Left(((), future)) => Either::Right(future),
Either::Right((r, _)) => Either::Left(r),
}
}