use std::{
future::Future,
sync::{Arc, Mutex},
time::{Duration, Instant},
};
use crate::{
errors::{PuppetError, RetryError},
message::ServiceCommand,
pid::Pid,
puppeteer::Puppeteer,
};
use async_trait::async_trait;
pub mod strategy {
#[derive(Debug, Clone, Copy)]
pub struct NoSupervision;
#[derive(Debug, Clone, Copy)]
pub struct OneToOne;
#[derive(Debug, Clone, Copy)]
pub struct OneForAll;
#[derive(Debug, Clone, Copy)]
pub struct RestForOne;
}
pub trait SupervisionStrategy: Send + Sync {
fn handle_failure(
pptr: &Puppeteer,
master: Pid,
puppet: Pid,
) -> impl Future<Output = Result<(), PuppetError>> + Send;
}
impl SupervisionStrategy for strategy::NoSupervision {
async fn handle_failure(
_pptr: &Puppeteer,
_master: Pid,
_puppet: Pid,
) -> Result<(), PuppetError> {
Ok(())
}
}
impl SupervisionStrategy for strategy::OneToOne {
async fn handle_failure(pptr: &Puppeteer, master: Pid, puppet: Pid) -> Result<(), PuppetError> {
Ok(pptr
.send_command_by_pid(master, puppet, ServiceCommand::Restart { stage: None })
.await?)
}
}
impl SupervisionStrategy for strategy::OneForAll {
async fn handle_failure(
pptr: &Puppeteer,
master: Pid,
_puppet: Pid,
) -> Result<(), PuppetError> {
if let Some(puppets) = pptr.get_puppets_by_pid(master) {
for pid in puppets.into_iter().rev() {
pptr.send_command_by_pid(master, pid, ServiceCommand::Restart { stage: None })
.await?;
}
}
Ok(())
}
}
impl SupervisionStrategy for strategy::RestForOne {
async fn handle_failure(pptr: &Puppeteer, master: Pid, puppet: Pid) -> Result<(), PuppetError> {
if let Some(puppets) = pptr.get_puppets_by_pid(master) {
let mut restart_next = false;
for pid in puppets.into_iter().rev() {
if pid == puppet {
restart_next = true;
}
if restart_next {
pptr.send_command_by_pid(master, pid, ServiceCommand::Restart { stage: None })
.await?;
}
}
}
Ok(())
}
}