use acton_ern::Ern;
use super::{BackoffDelay, RestartGeneration};
use crate::actor::{RestartStats, TerminationReason};
#[derive(Debug, Clone)]
pub struct ChildSupervised {
pub supervisor: Ern,
pub child: Ern,
pub restartable: bool,
}
impl ChildSupervised {
#[must_use]
pub const fn new(supervisor: Ern, child: Ern, restartable: bool) -> Self {
Self {
supervisor,
child,
restartable,
}
}
}
#[derive(Debug, Clone)]
pub struct ChildRestarted {
pub supervisor: Ern,
pub child: Ern,
pub generation: RestartGeneration,
pub reason: TerminationReason,
pub backoff: BackoffDelay,
}
impl ChildRestarted {
#[must_use]
pub const fn new(
supervisor: Ern,
child: Ern,
generation: RestartGeneration,
reason: TerminationReason,
backoff: BackoffDelay,
) -> Self {
Self {
supervisor,
child,
generation,
reason,
backoff,
}
}
}
#[derive(Debug, Clone)]
pub struct SupervisionEscalated {
pub supervisor: Ern,
pub child: Ern,
pub stats: RestartStats,
pub last_reason: TerminationReason,
}
impl SupervisionEscalated {
#[must_use]
pub const fn new(
supervisor: Ern,
child: Ern,
stats: RestartStats,
last_reason: TerminationReason,
) -> Self {
Self {
supervisor,
child,
stats,
last_reason,
}
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
use crate::traits::ActonMessage;
fn supervisor() -> Ern {
Ern::with_root("pool").expect("'pool' is a valid Ern root")
}
fn child() -> Ern {
Ern::with_root("worker-1").expect("'worker-1' is a valid Ern root")
}
fn stats() -> RestartStats {
RestartStats {
restarts_in_window: 5,
consecutive_restarts: 5,
window_secs: 60,
max_restarts: 5,
}
}
#[test]
fn child_supervised_carries_whether_the_child_can_be_recreated() {
let supervisor = supervisor();
let child = child();
let event = ChildSupervised::new(supervisor.clone(), child.clone(), true);
assert_eq!(event.supervisor, supervisor);
assert_eq!(event.child, child);
assert!(event.restartable);
let legacy = ChildSupervised::new(supervisor, child, false);
assert!(!legacy.restartable);
}
#[test]
fn child_restarted_names_the_incarnation_it_restarts_into() {
let event = ChildRestarted::new(
supervisor(),
child(),
RestartGeneration::FIRST.next(),
TerminationReason::Panic("boom".to_string()),
BackoffDelay::from(Duration::from_millis(200)),
);
assert_eq!(event.generation, RestartGeneration::FIRST.next());
assert_eq!(event.reason, TerminationReason::Panic("boom".to_string()));
assert_eq!(event.backoff.duration(), Duration::from_millis(200));
}
#[test]
fn supervision_escalated_carries_the_final_stats_and_reason() {
let event =
SupervisionEscalated::new(supervisor(), child(), stats(), TerminationReason::InboxClosed);
assert_eq!(event.stats.restarts_in_window, 5);
assert_eq!(event.stats.max_restarts, 5);
assert_eq!(event.last_reason, TerminationReason::InboxClosed);
}
#[test]
fn every_event_is_a_broadcastable_message() {
fn assert_message<M: ActonMessage>(_: &M) {}
assert_message(&ChildSupervised::new(supervisor(), child(), true));
assert_message(&ChildRestarted::new(
supervisor(),
child(),
RestartGeneration::FIRST,
TerminationReason::Normal,
BackoffDelay::NONE,
));
assert_message(&SupervisionEscalated::new(
supervisor(),
child(),
stats(),
TerminationReason::Normal,
));
}
}