use std::time::Duration;
#[cfg(feature = "report-serde")]
use serde::ser::{Serialize, SerializeStruct as _, Serializer};
use crate::signal::Signal;
use crate::sys::graceful::{GracefulOutcome, SoftDelivery};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SoftSignal {
Sent(Signal),
Unsupported,
Failed(Signal),
}
impl SoftSignal {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
SoftSignal::Sent(_) => "sent",
SoftSignal::Unsupported => "unsupported",
SoftSignal::Failed(_) => "failed",
}
}
pub(crate) fn signal(&self) -> Option<Signal> {
match self {
SoftSignal::Sent(signal) | SoftSignal::Failed(signal) => Some(*signal),
SoftSignal::Unsupported => None,
}
}
}
#[cfg(feature = "report-serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "report-serde")))]
impl Serialize for SoftSignal {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("SoftSignal", 2)?;
state.serialize_field(crate::report_serde::KIND, self.name())?;
state.serialize_field("signal", &self.signal())?;
state.end()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShutdownReport {
soft_signal: SoftSignal,
members_before: Option<usize>,
members_after: Option<usize>,
drained_within_grace: bool,
escalated: bool,
elapsed: Duration,
}
impl ShutdownReport {
pub(crate) fn from_outcome(outcome: GracefulOutcome, signal: Signal) -> Self {
let soft_signal = match outcome.soft {
SoftDelivery::Sent => SoftSignal::Sent(signal),
SoftDelivery::Unsupported => SoftSignal::Unsupported,
SoftDelivery::Failed => SoftSignal::Failed(signal),
};
Self {
soft_signal,
members_before: outcome.members_before,
members_after: outcome.members_after,
drained_within_grace: outcome.drained,
escalated: outcome.escalated,
elapsed: outcome.elapsed,
}
}
pub fn soft_signal(&self) -> SoftSignal {
self.soft_signal
}
pub fn attempted_signal(&self) -> Option<Signal> {
self.soft_signal.signal()
}
pub fn members_before(&self) -> Option<usize> {
self.members_before
}
pub fn members_after(&self) -> Option<usize> {
self.members_after
}
pub fn drained_within_grace(&self) -> bool {
self.drained_within_grace
}
pub fn escalated(&self) -> bool {
self.escalated
}
pub fn elapsed(&self) -> Duration {
self.elapsed
}
}
#[cfg(feature = "report-serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "report-serde")))]
impl Serialize for ShutdownReport {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let Self {
soft_signal,
members_before,
members_after,
drained_within_grace,
escalated,
elapsed,
} = self;
let mut state = serializer.serialize_struct("ShutdownReport", 6)?;
state.serialize_field("soft_signal", soft_signal)?;
state.serialize_field("members_before", members_before)?;
state.serialize_field("members_after", members_after)?;
state.serialize_field("drained_within_grace", drained_within_grace)?;
state.serialize_field("escalated", escalated)?;
state.serialize_field("elapsed_secs", &crate::report_serde::secs(*elapsed))?;
state.end()
}
}