Supervision; delayed actions; better tracing (incl `M: Debug`); linked task release
This commit is contained in:
parent
5861f91971
commit
d8c3e37d17
|
@ -64,7 +64,6 @@ fn assertions_at_existing_file(t: &mut Activation, ds: &Arc<Cap>, path: &PathBuf
|
||||||
}
|
}
|
||||||
for value in values.into_iter() {
|
for value in values.into_iter() {
|
||||||
if let Some(handle) = ds.assert(t, value.clone()) {
|
if let Some(handle) = ds.assert(t, value.clone()) {
|
||||||
tracing::debug!("asserted {:?} -> {:?}", value, handle);
|
|
||||||
handles.insert(handle);
|
handles.insert(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +189,6 @@ fn run(t: &mut Activation, ds: Arc<Cap>, captures: AnyValue) -> ActorResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for h in to_retract.into_iter() {
|
for h in to_retract.into_iter() {
|
||||||
tracing::debug!("retract {:?}", h);
|
|
||||||
t.retract(h);
|
t.retract(h);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -5,6 +5,7 @@ use syndicate::actor::*;
|
||||||
use syndicate::convert::*;
|
use syndicate::convert::*;
|
||||||
use syndicate::during::entity;
|
use syndicate::during::entity;
|
||||||
use syndicate::schemas::dataspace::Observe;
|
use syndicate::schemas::dataspace::Observe;
|
||||||
|
use syndicate::supervise::{Supervisor, SupervisorConfiguration};
|
||||||
use syndicate::value::NestedValue;
|
use syndicate::value::NestedValue;
|
||||||
|
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
@ -17,11 +18,14 @@ pub fn on_demand(t: &mut Activation, ds: Arc<Cap>, gateway: Arc<Cap>) {
|
||||||
let monitor = entity(())
|
let monitor = entity(())
|
||||||
.on_asserted_facet({
|
.on_asserted_facet({
|
||||||
let ds = Arc::clone(&ds);
|
let ds = Arc::clone(&ds);
|
||||||
move |_, t, captures| {
|
move |_, t, captures: AnyValue| {
|
||||||
let ds = Arc::clone(&ds);
|
let ds = Arc::clone(&ds);
|
||||||
let gateway = Arc::clone(&gateway);
|
let gateway = Arc::clone(&gateway);
|
||||||
t.spawn_link(syndicate::name!(parent: None, "relay", addr = ?captures),
|
Supervisor::start(
|
||||||
|t| run(t, ds, gateway, captures));
|
t,
|
||||||
|
syndicate::name!(parent: None, "relay", addr = ?captures),
|
||||||
|
SupervisorConfiguration::default(),
|
||||||
|
move |t| run(t, Arc::clone(&ds), Arc::clone(&gateway), captures.clone()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,7 +19,7 @@ preserves-schema = "0.8.0"
|
||||||
preserves = "0.20.0"
|
preserves = "0.20.0"
|
||||||
preserves-schema = "0.8.0"
|
preserves-schema = "0.8.0"
|
||||||
|
|
||||||
tokio = { version = "1.10.0", features = ["io-util", "macros", "rt", "rt-multi-thread"] }
|
tokio = { version = "1.10.0", features = ["io-util", "macros", "rt", "rt-multi-thread", "time"] }
|
||||||
tokio-util = "0.6.7"
|
tokio-util = "0.6.7"
|
||||||
bytes = "1.0.1"
|
bytes = "1.0.1"
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ use std::sync::Mutex;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
|
||||||
|
use std::time;
|
||||||
|
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
|
@ -69,8 +70,12 @@ pub type ActorResult = Result<(), Error>;
|
||||||
/// the actor's mainloop task.
|
/// the actor's mainloop task.
|
||||||
pub type ActorHandle = tokio::task::JoinHandle<ActorResult>;
|
pub type ActorHandle = tokio::task::JoinHandle<ActorResult>;
|
||||||
|
|
||||||
|
/// The type of the "disarm" function returned from [`Activation::prevent_inert_check`].
|
||||||
|
pub type DisarmFn = Box<dyn Send + FnOnce()>;
|
||||||
|
|
||||||
/// A small protocol for indicating successful synchronisation with
|
/// A small protocol for indicating successful synchronisation with
|
||||||
/// some peer; see [Entity::sync].
|
/// some peer; see [Entity::sync].
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Synced;
|
pub struct Synced;
|
||||||
|
|
||||||
/// The core metaprotocol implemented by every object.
|
/// The core metaprotocol implemented by every object.
|
||||||
|
@ -594,15 +599,19 @@ impl<'activation> Activation<'activation> {
|
||||||
/// Core API: assert `a` at recipient `r`.
|
/// Core API: assert `a` at recipient `r`.
|
||||||
///
|
///
|
||||||
/// Returns the [`Handle`] for the new assertion.
|
/// Returns the [`Handle`] for the new assertion.
|
||||||
pub fn assert<M: 'static + Send>(&mut self, r: &Arc<Ref<M>>, a: M) -> Handle {
|
pub fn assert<M: 'static + Send + std::fmt::Debug>(&mut self, r: &Arc<Ref<M>>, a: M) -> Handle {
|
||||||
let handle = next_handle();
|
let handle = next_handle();
|
||||||
if let Some(f) = self.active_facet() {
|
if let Some(f) = self.active_facet() {
|
||||||
|
tracing::trace!(?r, ?handle, ?a, "assert");
|
||||||
f.insert_retract_cleanup_action(&r, handle);
|
f.insert_retract_cleanup_action(&r, handle);
|
||||||
drop(f);
|
drop(f);
|
||||||
{
|
{
|
||||||
let r = Arc::clone(r);
|
let r = Arc::clone(r);
|
||||||
self.pending.queue_for(&r).push(Box::new(
|
self.pending.queue_for(&r).push(Box::new(
|
||||||
move |t| t.with_entity(&r, |t, e| e.assert(t, a, handle))));
|
move |t| t.with_entity(&r, |t, e| {
|
||||||
|
tracing::trace!(?handle, ?a, "asserted");
|
||||||
|
e.assert(t, a, handle)
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle
|
handle
|
||||||
|
@ -622,22 +631,29 @@ impl<'activation> Activation<'activation> {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `r` is not part of the active actor.
|
/// Panics if `r` is not part of the active actor.
|
||||||
pub fn assert_for_myself<M: 'static + Send>(&mut self, r: &Arc<Ref<M>>, a: M) -> Handle {
|
pub fn assert_for_myself<M: 'static + Send + std::fmt::Debug>(&mut self, r: &Arc<Ref<M>>, a: M) -> Handle {
|
||||||
self.immediate_oid(r);
|
self.immediate_oid(r);
|
||||||
let handle = next_handle();
|
let handle = next_handle();
|
||||||
if let Some(f) = self.active_facet() {
|
if let Some(f) = self.active_facet() {
|
||||||
|
tracing::trace!(?r, ?handle, ?a, "assert_for_myself");
|
||||||
{
|
{
|
||||||
let r = Arc::clone(r);
|
let r = Arc::clone(r);
|
||||||
f.cleanup_actions.insert(
|
f.cleanup_actions.insert(
|
||||||
handle,
|
handle,
|
||||||
CleanupAction::ForMyself(Box::new(
|
CleanupAction::ForMyself(Box::new(
|
||||||
move |t| t.with_entity(&r, |t, e| e.retract(t, handle)))));
|
move |t| t.with_entity(&r, |t, e| {
|
||||||
|
tracing::trace!(?handle, "retracted");
|
||||||
|
e.retract(t, handle)
|
||||||
|
}))));
|
||||||
}
|
}
|
||||||
drop(f);
|
drop(f);
|
||||||
{
|
{
|
||||||
let r = Arc::clone(r);
|
let r = Arc::clone(r);
|
||||||
self.pending.for_myself.push(Box::new(
|
self.pending.for_myself.push(Box::new(
|
||||||
move |t| t.with_entity(&r, |t, e| e.assert(t, a, handle))));
|
move |t| t.with_entity(&r, |t, e| {
|
||||||
|
tracing::trace!(?handle, ?a, "asserted");
|
||||||
|
e.assert(t, a, handle)
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle
|
handle
|
||||||
|
@ -646,6 +662,7 @@ impl<'activation> Activation<'activation> {
|
||||||
fn half_link(&mut self, t_other: &mut Activation) {
|
fn half_link(&mut self, t_other: &mut Activation) {
|
||||||
let entity_ref = t_other.create::<AnyValue, _>(StopOnRetract);
|
let entity_ref = t_other.create::<AnyValue, _>(StopOnRetract);
|
||||||
let handle = next_handle();
|
let handle = next_handle();
|
||||||
|
tracing::trace!(?handle, ?entity_ref, "half_link");
|
||||||
self.active_facet().unwrap().insert_retract_cleanup_action(&entity_ref, handle);
|
self.active_facet().unwrap().insert_retract_cleanup_action(&entity_ref, handle);
|
||||||
t_other.with_entity(&entity_ref, |t, e| e.assert(t, AnyValue::new(true), handle)).unwrap();
|
t_other.with_entity(&entity_ref, |t, e| e.assert(t, AnyValue::new(true), handle)).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -660,10 +677,14 @@ impl<'activation> Activation<'activation> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Core API: send message `m` to recipient `r`.
|
/// Core API: send message `m` to recipient `r`.
|
||||||
pub fn message<M: 'static + Send>(&mut self, r: &Arc<Ref<M>>, m: M) {
|
pub fn message<M: 'static + Send + std::fmt::Debug>(&mut self, r: &Arc<Ref<M>>, m: M) {
|
||||||
|
tracing::trace!(?r, ?m, "message");
|
||||||
let r = Arc::clone(r);
|
let r = Arc::clone(r);
|
||||||
self.pending.queue_for(&r).push(Box::new(
|
self.pending.queue_for(&r).push(Box::new(
|
||||||
move |t| t.with_entity(&r, |t, e| e.message(t, m))))
|
move |t| t.with_entity(&r, |t, e| {
|
||||||
|
tracing::trace!(?m, "delivered");
|
||||||
|
e.message(t, m)
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Core API: send message `m` to recipient `r`, which must be a
|
/// Core API: send message `m` to recipient `r`, which must be a
|
||||||
|
@ -766,6 +787,7 @@ impl<'activation> Activation<'activation> {
|
||||||
boot: F,
|
boot: F,
|
||||||
) {
|
) {
|
||||||
let mailbox = self.state.mailbox();
|
let mailbox = self.state.mailbox();
|
||||||
|
let facet = self.facet.clone();
|
||||||
if let Some(f) = self.active_facet() {
|
if let Some(f) = self.active_facet() {
|
||||||
let token = CancellationToken::new();
|
let token = CancellationToken::new();
|
||||||
let task_id = NEXT_TASK_ID.fetch_add(BUMP_AMOUNT.into(), Ordering::Relaxed);
|
let task_id = NEXT_TASK_ID.fetch_add(BUMP_AMOUNT.into(), Ordering::Relaxed);
|
||||||
|
@ -774,7 +796,7 @@ impl<'activation> Activation<'activation> {
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tracing::trace!(task_id, "linked task start");
|
tracing::trace!(task_id, "linked task start");
|
||||||
select! {
|
let result = select! {
|
||||||
_ = token.cancelled() => {
|
_ = token.cancelled() => {
|
||||||
tracing::trace!(task_id, "linked task cancelled");
|
tracing::trace!(task_id, "linked task cancelled");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -793,13 +815,40 @@ impl<'activation> Activation<'activation> {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
let _ = facet.activate(
|
||||||
|
Account::new(crate::name!("release_linked_task")), |t| {
|
||||||
|
if let Some(f) = t.active_facet() {
|
||||||
|
tracing::trace!(task_id, "cancellation token removed");
|
||||||
|
f.linked_tasks.remove(&task_id);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
result
|
||||||
}.instrument(name));
|
}.instrument(name));
|
||||||
}
|
}
|
||||||
f.linked_tasks.insert(task_id, token);
|
f.linked_tasks.insert(task_id, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes the given action after the given duration has elapsed (so long as the active
|
||||||
|
/// facet still exists at that time).
|
||||||
|
pub fn after(&mut self, duration: time::Duration, a: Action) {
|
||||||
|
self.at(time::Instant::now() + duration, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the given action at the given instant (so long as the active facet still
|
||||||
|
/// exists at that time).
|
||||||
|
pub fn at<I: Into<tokio::time::Instant>>(&mut self, instant: I, a: Action) {
|
||||||
|
let facet = self.facet.clone();
|
||||||
|
let account = Arc::clone(self.account());
|
||||||
|
let instant = instant.into();
|
||||||
|
self.linked_task(crate::name!("Activation::at"), async move {
|
||||||
|
tokio::time::sleep_until(instant.into()).await;
|
||||||
|
facet.activate(account, a)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn enqueue_for_myself_at_commit(&mut self, action: Action) {
|
fn enqueue_for_myself_at_commit(&mut self, action: Action) {
|
||||||
let mailbox = self.state.mailbox();
|
let mailbox = self.state.mailbox();
|
||||||
self.pending.queue_for_mailbox(&mailbox).push(action);
|
self.pending.queue_for_mailbox(&mailbox).push(action);
|
||||||
|
@ -868,7 +917,7 @@ impl<'activation> Activation<'activation> {
|
||||||
/// its life, the Dataspace actor will have no outbound assertions, no child facets, and no
|
/// its life, the Dataspace actor will have no outbound assertions, no child facets, and no
|
||||||
/// linked tasks, so the only way to prevent it from being prematurely garbage collected is
|
/// linked tasks, so the only way to prevent it from being prematurely garbage collected is
|
||||||
/// to use `prevent_inert_check` in its boot function.
|
/// to use `prevent_inert_check` in its boot function.
|
||||||
pub fn prevent_inert_check(&mut self) -> Box<dyn FnOnce()> {
|
pub fn prevent_inert_check(&mut self) -> DisarmFn {
|
||||||
if let Some(f) = self.active_facet() {
|
if let Some(f) = self.active_facet() {
|
||||||
Box::new(f.prevent_inert_check())
|
Box::new(f.prevent_inert_check())
|
||||||
} else {
|
} else {
|
||||||
|
@ -986,6 +1035,7 @@ impl EventBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deliver(&mut self) {
|
fn deliver(&mut self) {
|
||||||
|
tracing::trace!("EventBuffer::deliver");
|
||||||
if !self.for_myself.is_empty() {
|
if !self.for_myself.is_empty() {
|
||||||
panic!("Unprocessed for_myself events remain at deliver() time");
|
panic!("Unprocessed for_myself events remain at deliver() time");
|
||||||
}
|
}
|
||||||
|
@ -1223,7 +1273,8 @@ impl Actor {
|
||||||
if r.is_err() { return; }
|
if r.is_err() { return; }
|
||||||
}
|
}
|
||||||
SystemMessage::Crash(e) => {
|
SystemMessage::Crash(e) => {
|
||||||
tracing::trace!(actor_id = ?self.ac_ref.actor_id, "SystemMessage::Crash({:?})", &e);
|
tracing::trace!(actor_id = ?self.ac_ref.actor_id,
|
||||||
|
"SystemMessage::Crash({:?})", &e);
|
||||||
return terminate(Err(e));
|
return terminate(Err(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1264,7 +1315,10 @@ impl Facet {
|
||||||
self.cleanup_actions.insert(
|
self.cleanup_actions.insert(
|
||||||
handle,
|
handle,
|
||||||
CleanupAction::ForAnother(Arc::clone(&r.mailbox), Box::new(
|
CleanupAction::ForAnother(Arc::clone(&r.mailbox), Box::new(
|
||||||
move |t| t.with_entity(&r, |t, e| e.retract(t, handle)))));
|
move |t| t.with_entity(&r, |t, e| {
|
||||||
|
tracing::trace!(?handle, "retracted");
|
||||||
|
e.retract(t, handle)
|
||||||
|
}))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub mod error;
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
pub mod relay;
|
pub mod relay;
|
||||||
pub mod rewrite;
|
pub mod rewrite;
|
||||||
|
pub mod supervise;
|
||||||
|
|
||||||
pub mod schemas {
|
pub mod schemas {
|
||||||
//! Auto-generated codecs for [Syndicate protocol
|
//! Auto-generated codecs for [Syndicate protocol
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
//! Extremely simple single-actor supervision. Vastly simplified compared to the available
|
||||||
|
//! options in [Erlang/OTP](https://erlang.org/doc/man/supervisor.html).
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
|
use crate::actor::*;
|
||||||
|
|
||||||
|
enum Protocol<Boot: 'static + Send + FnMut(&mut Activation) -> ActorResult> {
|
||||||
|
SuperviseeStarted, // assertion
|
||||||
|
BootFunction(Boot), // message
|
||||||
|
Retry, // message
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SupervisorConfiguration {
|
||||||
|
pub intensity: usize,
|
||||||
|
pub period: Duration,
|
||||||
|
pub pause_time: Duration,
|
||||||
|
pub sleep_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Supervisor<Boot: 'static + Send + FnMut(&mut Activation) -> ActorResult> {
|
||||||
|
self_ref: Arc<Ref<Protocol<Boot>>>,
|
||||||
|
name: tracing::Span,
|
||||||
|
config: SupervisorConfiguration,
|
||||||
|
boot_fn: Option<Boot>,
|
||||||
|
restarts: VecDeque<Instant>,
|
||||||
|
supervisee: Supervisee,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum Supervisee {
|
||||||
|
NotRunning,
|
||||||
|
Booting,
|
||||||
|
Running,
|
||||||
|
Recovering,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Boot: 'static + Send + FnMut(&mut Activation) -> ActorResult> std::fmt::Debug for Protocol<Boot> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Protocol::SuperviseeStarted => write!(f, "Protocol::SuperviseeStarted"),
|
||||||
|
Protocol::BootFunction(_) => write!(f, "Protocol::BootFunction(_)"),
|
||||||
|
Protocol::Retry => write!(f, "Protocol::Retry"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SupervisorConfiguration {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
intensity: 1,
|
||||||
|
period: Duration::from_secs(5),
|
||||||
|
pause_time: Duration::from_millis(200),
|
||||||
|
sleep_time: Duration::from_secs(10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Boot: 'static + Send + FnMut(&mut Activation) -> ActorResult>
|
||||||
|
Entity<Protocol<Boot>> for Supervisor<Boot>
|
||||||
|
{
|
||||||
|
fn assert(&mut self, _t: &mut Activation, m: Protocol<Boot>, _h: Handle) -> ActorResult {
|
||||||
|
match m {
|
||||||
|
Protocol::SuperviseeStarted => self.enter_state(Supervisee::Booting),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn retract(&mut self, t: &mut Activation, _h: Handle) -> ActorResult {
|
||||||
|
self.enter_state(Supervisee::Recovering);
|
||||||
|
let now = Instant::now();
|
||||||
|
let oldest_to_keep = now - self.config.period;
|
||||||
|
self.restarts.push_back(now);
|
||||||
|
while let Some(stamp) = self.restarts.front() {
|
||||||
|
if stamp < &oldest_to_keep {
|
||||||
|
self.restarts.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let self_ref = Arc::clone(&self.self_ref);
|
||||||
|
let wait_time = if self.restarts.len() > self.config.intensity {
|
||||||
|
self.config.sleep_time
|
||||||
|
} else {
|
||||||
|
self.config.pause_time
|
||||||
|
};
|
||||||
|
t.after(wait_time, Box::new(move |t| {
|
||||||
|
t.message(&self_ref, Protocol::Retry);
|
||||||
|
Ok(())
|
||||||
|
}));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message(&mut self, t: &mut Activation, m: Protocol<Boot>) -> ActorResult {
|
||||||
|
match m {
|
||||||
|
Protocol::BootFunction(b) => {
|
||||||
|
self.enter_state(Supervisee::Running);
|
||||||
|
self.boot_fn = Some(b);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Protocol::Retry => {
|
||||||
|
self.enter_state(Supervisee::NotRunning);
|
||||||
|
self.ensure_started(t)
|
||||||
|
}
|
||||||
|
_ => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Boot: 'static + Send + FnMut(&mut Activation) -> ActorResult> Supervisor<Boot> {
|
||||||
|
pub fn start(
|
||||||
|
t: &mut Activation,
|
||||||
|
name: tracing::Span,
|
||||||
|
config: SupervisorConfiguration,
|
||||||
|
boot_fn: Boot,
|
||||||
|
) {
|
||||||
|
tracing::trace!(?config);
|
||||||
|
let self_ref = t.create_inert();
|
||||||
|
let mut supervisor = Supervisor {
|
||||||
|
self_ref: Arc::clone(&self_ref),
|
||||||
|
name,
|
||||||
|
config,
|
||||||
|
boot_fn: Some(boot_fn),
|
||||||
|
restarts: VecDeque::new(),
|
||||||
|
supervisee: Supervisee::NotRunning,
|
||||||
|
};
|
||||||
|
|
||||||
|
// In cases where we are the only Entity in our Facet, and our
|
||||||
|
// supervisee terminates, we will often be "inert" until we
|
||||||
|
// can restart it. So we prevent_inert_check to signal to the
|
||||||
|
// system that there's something going on for that moment of
|
||||||
|
// time between the supervisee terminating and our responding
|
||||||
|
// to it.
|
||||||
|
let _ = t.prevent_inert_check();
|
||||||
|
|
||||||
|
supervisor.ensure_started(t).unwrap();
|
||||||
|
self_ref.become_entity(supervisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_state(&mut self, supervisee: Supervisee) {
|
||||||
|
let _entry = self.name.enter();
|
||||||
|
tracing::info!("{:?} --> {:?}", self.supervisee, supervisee);
|
||||||
|
self.supervisee = supervisee;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_started(&mut self, t: &mut Activation) -> ActorResult {
|
||||||
|
match self.boot_fn.take() {
|
||||||
|
None =>
|
||||||
|
tracing::error!("Cannot restart supervisee, because it panicked at startup"),
|
||||||
|
Some(mut boot_fn) => {
|
||||||
|
let self_ref = Arc::clone(&self.self_ref);
|
||||||
|
t.facet(|t: &mut Activation| {
|
||||||
|
t.assert(&self.self_ref, Protocol::SuperviseeStarted);
|
||||||
|
t.spawn_link(crate::name!(parent: &self.name, "supervisee"), move |t| {
|
||||||
|
match boot_fn(t) {
|
||||||
|
Ok(()) => {
|
||||||
|
t.message(&self_ref, Protocol::BootFunction(boot_fn));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
t.clear();
|
||||||
|
t.message(&self_ref, Protocol::BootFunction(boot_fn));
|
||||||
|
t.deliver();
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue