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