You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.7 KiB
147 lines
3.7 KiB
4 years ago
|
//! Handles spawning and restarting service task(s)
|
||
|
use super::*;
|
||
|
use tokio::sync::RwLock;
|
||
|
use std::mem::MaybeUninit;
|
||
|
use std::ops;
|
||
|
use futures::future::Future;
|
||
|
|
||
|
const SUPERVISOR_BACKLOG: usize = 32;
|
||
|
|
||
|
mod dispatch; pub use dispatch::*;
|
||
|
|
||
|
/// Signal the shutdown method to the supervisor.
|
||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
||
|
pub enum SupervisorControl
|
||
|
{
|
||
|
/// Normal working
|
||
|
Initialise,
|
||
|
/// Signal the subtask(s) to shut down, then wait for them and exit.
|
||
|
Signal,
|
||
|
/// Drop all handles and pipes to subtask(s) then immediately exit.
|
||
|
Drop,
|
||
|
/// Restart any and all subtask(s)
|
||
|
Restart,
|
||
|
|
||
|
/// Set the max task limit. Default is 0.
|
||
|
TaskLimit(usize),
|
||
|
}
|
||
|
|
||
|
impl Default for SupervisorControl
|
||
|
{
|
||
|
#[inline]
|
||
|
fn default() -> Self
|
||
|
{
|
||
|
Self::Initialise
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Supervisor responsible for spawning the state handler service.
|
||
|
#[derive(Debug)]
|
||
|
pub(super) struct Supervisor
|
||
|
{
|
||
|
/// Handle for the supervisor task itself
|
||
|
handle: JoinHandle<ExitStatus>,
|
||
|
|
||
|
/// Watch sender for signalling shutdowns the supervisor task itself
|
||
|
shutdown: watch::Sender<SupervisorControl>,
|
||
|
|
||
|
/// The pipe to send requests to the supervisor's subtasks
|
||
|
pipe: mpsc::Sender<ServiceRequest>,
|
||
|
|
||
|
/// The initial receiver created from `broadcast_root`.
|
||
|
broadcast_receiver: broadcast::Receiver<ServiceEvent>,
|
||
|
|
||
|
/// Data shared between the supervisor's task and its controller instance here.
|
||
|
shared: Arc<SupervisorShared>,
|
||
|
}
|
||
|
|
||
|
/// Object shared btweeen the Supervisor control instance and its supervisor task.
|
||
|
#[derive(Debug)]
|
||
|
struct SupervisorShared
|
||
|
{
|
||
|
//// scratch that, idk what this was supposed to be for. I'm sure i'll remember if it's important.
|
||
|
//sub: RwLock<BTreeMap<ServiceEventKind, ServiceEvent>>,
|
||
|
|
||
|
broadcast_root: broadcast::Sender<ServiceEvent>,
|
||
|
state: state::State,
|
||
|
}
|
||
|
|
||
|
/// The state held by the running superviser service
|
||
|
#[derive(Debug)]
|
||
|
struct SupervisorTaskState
|
||
|
{
|
||
|
shutdown: watch::Receiver<SupervisorControl>,
|
||
|
recv: mpsc::Receiver<ServiceRequest>,
|
||
|
shared: Arc<SupervisorShared>,
|
||
|
}
|
||
|
|
||
|
impl Supervisor
|
||
|
{
|
||
|
/// Attempt to send a control signal to the supervisor itself
|
||
|
pub fn signal_control(&self, sig: SupervisorControl) -> Result<(), watch::error::SendError<SupervisorControl>>
|
||
|
{
|
||
|
self.shutdown.broadcast(sig)?;
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
/// Drop all communications with background worker and wait for it to complete
|
||
|
pub async fn join_now(self) -> eyre::Result<()>
|
||
|
{
|
||
|
let handle = {
|
||
|
let Self { handle, ..} = self; // drop everything else
|
||
|
handle
|
||
|
};
|
||
|
handle.await?;
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
/// Check if the background worker has not been dropped.
|
||
|
///
|
||
|
/// If this returns false it usually indicates a fatal error.
|
||
|
pub fn is_alive(&self) -> bool
|
||
|
{
|
||
|
Arc::strong_count(&self.shared) > 1
|
||
|
}
|
||
|
|
||
|
/// Create a new supervisor for this state.
|
||
|
pub fn new(state: state::State) -> Self
|
||
|
{
|
||
|
let shutdown = watch::channel(Default::default());
|
||
|
let pipe = mpsc::channel(SUPERVISOR_BACKLOG);
|
||
|
let (broadcast_root, broadcast_receiver) = broadcast::channel(SUPERVISOR_BACKLOG);
|
||
|
|
||
|
let shared = Arc::new(SupervisorShared{
|
||
|
broadcast_root,
|
||
|
state,
|
||
|
});
|
||
|
|
||
|
let (shutdown_0, shutdown_1) = shutdown;
|
||
|
let (pipe_0, pipe_1) = pipe;
|
||
|
|
||
|
Self {
|
||
|
shutdown: shutdown_0,
|
||
|
pipe: pipe_0,
|
||
|
broadcast_receiver,
|
||
|
shared: Arc::clone(&shared),
|
||
|
|
||
|
handle: tokio::spawn(async move {
|
||
|
let shared = shared;
|
||
|
ExitStatus::from(service_fn(SupervisorTaskState {
|
||
|
shared,
|
||
|
recv: pipe_1,
|
||
|
shutdown: shutdown_1,
|
||
|
}).await)
|
||
|
}),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn service_fn(mut state: SupervisorTaskState) -> eyre::Result<()>
|
||
|
{
|
||
|
while let Some(req) = state.recv.recv().await {
|
||
|
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|