use bombay_address::{Lease, RegistrationId};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LifecycleTransition {
Prepared,
Started,
ShutdownRequested,
Restarted,
Retired,
Completed,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LifecycleEvent<A, I = RegistrationId> {
pub address: A,
pub incarnation: I,
pub transition: LifecycleTransition,
}
pub trait LifecycleSink<A, I>: Clone + Send + Sync {
fn record(&self, event: LifecycleEvent<A, I>);
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NoLifecycle;
#[doc(hidden)]
#[derive(Clone)]
pub struct Lifecycle<S>(pub(crate) S);
pub trait RegistrationIdentity {
type Identity: Clone + Send + Sync + 'static;
fn registration_identity(&self) -> Self::Identity;
}
impl<A, E> RegistrationIdentity for Lease<A, E>
where
A: Eq + core::hash::Hash,
{
type Identity = RegistrationId;
fn registration_identity(&self) -> Self::Identity {
self.registration_id()
}
}
#[doc(hidden)]
pub trait IncarnationReporter: Clone + Send + Sync + 'static {
fn emit(&self, transition: LifecycleTransition);
}
impl IncarnationReporter for NoLifecycle {
fn emit(&self, _transition: LifecycleTransition) {}
}
#[derive(Clone)]
#[doc(hidden)]
pub struct Reporting<A, I, S> {
address: A,
incarnation: I,
sink: S,
}
impl<A, I, S> IncarnationReporter for Reporting<A, I, S>
where
A: Clone + Send + Sync + 'static,
I: Clone + Send + Sync + 'static,
S: LifecycleSink<A, I> + 'static,
{
fn emit(&self, transition: LifecycleTransition) {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
self.sink.record(LifecycleEvent {
address: self.address.clone(),
incarnation: self.incarnation.clone(),
transition,
});
}));
}
}
#[doc(hidden)]
pub trait LifecycleFactory<A, R>: Clone {
type Reporter: IncarnationReporter;
fn reporter(&self, address: A, registration: &R) -> Self::Reporter;
}
impl<A, R> LifecycleFactory<A, R> for NoLifecycle {
type Reporter = NoLifecycle;
fn reporter(&self, _address: A, _registration: &R) -> Self::Reporter {
NoLifecycle
}
}
impl<A, R, S> LifecycleFactory<A, R> for Lifecycle<S>
where
A: Clone + Send + Sync + 'static,
R: RegistrationIdentity,
S: LifecycleSink<A, R::Identity> + 'static,
{
type Reporter = Reporting<A, R::Identity, S>;
fn reporter(&self, address: A, registration: &R) -> Self::Reporter {
Reporting {
address,
incarnation: registration.registration_identity(),
sink: self.0.clone(),
}
}
}