parent
4e71299f37
commit
c51f87e8cb
@ -0,0 +1,28 @@
|
||||
use super::*;
|
||||
use std::any::Any;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CommandKind
|
||||
{
|
||||
/// Shutdown gracefully.
|
||||
///
|
||||
/// # Response
|
||||
/// None.
|
||||
GracefulShutdown,
|
||||
}
|
||||
|
||||
/// A response from the interrupt channel.
|
||||
/// Some command kinds may warrant a response.
|
||||
pub type CommandResponse = Box<dyn Any + Send + 'static>;
|
||||
|
||||
/// A command to interrupt the web background task.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Command
|
||||
{
|
||||
pub(super) kind: CommandKind,
|
||||
pub(super) response: oneshot::Sender<CommandResponse>, // If the interrupt stream produces no response for this query, the sender will just be dropped and the receiver will `Err`.
|
||||
}
|
||||
|
||||
/// A channel to communicate with background task
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InterruptChannel(pub(super) mpsc::Sender<Command>);
|
@ -0,0 +1,83 @@
|
||||
use super::*;
|
||||
|
||||
use state::State;
|
||||
use futures::prelude::*;
|
||||
use tokio::{
|
||||
sync::{
|
||||
mpsc,
|
||||
oneshot,
|
||||
},
|
||||
};
|
||||
|
||||
mod command;
|
||||
pub use command::*;
|
||||
|
||||
/// Serve this state with this interrupt signal
|
||||
pub fn serve(state: State) -> (InterruptChannel, impl Future<Output = eyre::Result<()>> + 'static)
|
||||
{
|
||||
// interrupt handler
|
||||
let (int_tx, mut int_rx) = mpsc::channel::<Command>(16);
|
||||
let (grace_tx, grace_rx) = oneshot::channel::<()>();
|
||||
let (s_int_tx, s_int_rx) = oneshot::channel::<()>();
|
||||
|
||||
// When this future completes, the server will initiate a graceful shutdown.
|
||||
let graceful_shutdown = async move {
|
||||
tokio::select!{
|
||||
//_ = tokio::signal::ctrl_c() =>{} //The caller should handle this and then send `InterruptChannel` a `GracefulShutdown` event.
|
||||
_ = grace_rx => {}
|
||||
}
|
||||
};
|
||||
|
||||
let h_int = tokio::spawn(async move {
|
||||
let work = async {
|
||||
// Handle commands from interrupt channel.
|
||||
while let Some(com) = int_rx.recv().await
|
||||
{
|
||||
let resp = com.response; //sender for response
|
||||
match com.kind {
|
||||
CommandKind::GracefulShutdown => {
|
||||
report!(grace_tx.send(()));
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
let int = async {
|
||||
let _ = tokio::join![
|
||||
//tokio::signal::ctrl_c(),
|
||||
s_int_rx,
|
||||
];
|
||||
};
|
||||
tokio::select!{
|
||||
_ = int => {info!("h_int shutdown due to interrupt");},
|
||||
_ = work => {info!("h_int shutdown due to exhausted work stream or shutdown signal");},
|
||||
}
|
||||
});
|
||||
let command_channel = InterruptChannel(int_tx);
|
||||
|
||||
// setup server
|
||||
let server = {
|
||||
// TODO: warp routing paths
|
||||
clone!(command_channel);
|
||||
async move {
|
||||
mv![command_channel, // If we need to send commands to our own stream
|
||||
state, // The program state
|
||||
graceful_shutdown, // The graceful shutdown Future for warp.
|
||||
//TODO: routing paths
|
||||
];
|
||||
|
||||
// TODO: warp::try_serve...
|
||||
}
|
||||
};
|
||||
(command_channel,
|
||||
async move {
|
||||
info!("Waiting on server future");
|
||||
tokio::join![
|
||||
server,
|
||||
h_int,
|
||||
].1?;
|
||||
|
||||
report!(s_int_tx.send(()));
|
||||
Ok(())
|
||||
})
|
||||
}
|
Loading…
Reference in new issue