From d5e3c92bce41e297a5f924b05076ac15ce83dc61 Mon Sep 17 00:00:00 2001 From: Sean Lawlor Date: Fri, 17 May 2024 21:45:53 -0400 Subject: [PATCH] Prep for 0.10.0 release (#238) * Update readmes for 0.10.0 release * Adjust inconsistent naming with `SpawnErr` and `ActorErr` since panic isn't the only "failure", actors can return a regular Error as well Resolves #164 --- README.md | 2 +- ractor/examples/supervisor.rs | 4 ++-- ractor/src/actor/actor_cell.rs | 4 ++-- ractor/src/actor/messages.rs | 12 +++++------ ractor/src/actor/mod.rs | 24 ++++++++++----------- ractor/src/actor/tests/mod.rs | 6 +++--- ractor/src/actor/tests/supervisor.rs | 20 ++++++++--------- ractor/src/errors.rs | 24 +++++++-------------- ractor/src/factory/factoryimpl.rs | 2 +- ractor/src/lib.rs | 2 +- ractor/src/tests.rs | 4 ---- ractor_cluster/src/net/session.rs | 2 +- ractor_cluster/src/node/mod.rs | 2 +- ractor_cluster/src/node/node_session/mod.rs | 2 +- 14 files changed, 49 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 9fc0a3b3..a3b75771 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Install `ractor` by adding the following to your Cargo.toml dependencies. ```toml [dependencies] -ractor = "0.9" +ractor = "0.10" ``` The minimum supported Rust version (MSRV) of `ractor` is `1.64`. However to utilize the native `async fn` support in traits and not rely on the `async-trait` crate's desugaring functionliaty, you need to be on Rust version `>= 1.75`. The stabilization of `async fn` in traits [was recently added](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html). diff --git a/ractor/examples/supervisor.rs b/ractor/examples/supervisor.rs index 32649f8b..9a6f6bb6 100644 --- a/ractor/examples/supervisor.rs +++ b/ractor/examples/supervisor.rs @@ -209,7 +209,7 @@ impl Actor for MidLevelActor { state: &mut Self::State, ) -> Result<(), ActorProcessingErr> { match message { - SupervisionEvent::ActorPanicked(dead_actor, panic_msg) + SupervisionEvent::ActorFailed(dead_actor, panic_msg) if dead_actor.get_id() == state.leaf_actor.get_id() => { tracing::info!("MidLevelActor: {dead_actor:?} panicked with '{panic_msg}'"); @@ -295,7 +295,7 @@ impl Actor for RootActor { state: &mut Self::State, ) -> Result<(), ActorProcessingErr> { match message { - SupervisionEvent::ActorPanicked(dead_actor, panic_msg) + SupervisionEvent::ActorFailed(dead_actor, panic_msg) if dead_actor.get_id() == state.mid_level_actor.get_id() => { tracing::info!("RootActor: {dead_actor:?} panicked with '{panic_msg}'"); diff --git a/ractor/src/actor/actor_cell.rs b/ractor/src/actor/actor_cell.rs index f78b75be..df288adf 100644 --- a/ractor/src/actor/actor_cell.rs +++ b/ractor/src/actor/actor_cell.rs @@ -253,14 +253,14 @@ impl ActorCell { TActor: Actor, { if id.is_local() { - return Err(SpawnErr::StartupPanic(From::from("Cannot create a new remote actor handler without the actor id being marked as a remote actor!"))); + return Err(SpawnErr::StartupFailed(From::from("Cannot create a new remote actor handler without the actor id being marked as a remote actor!"))); } let (props, rx1, rx2, rx3, rx4) = ActorProperties::new_remote::(name, id); let cell = Self { inner: Arc::new(props), }; - // TODO: remote actors don't appear in the name registry + // NOTE: remote actors don't appear in the name registry // if let Some(r_name) = name { // crate::registry::register(r_name, cell.clone())?; // } diff --git a/ractor/src/actor/messages.rs b/ractor/src/actor/messages.rs index d97cb8de..9099a966 100644 --- a/ractor/src/actor/messages.rs +++ b/ractor/src/actor/messages.rs @@ -90,8 +90,8 @@ pub enum SupervisionEvent { Option, Option, ), - /// An actor panicked - ActorPanicked(super::actor_cell::ActorCell, ActorProcessingErr), + /// An actor failed (due to panic or error case) + ActorFailed(super::actor_cell::ActorCell, ActorProcessingErr), /// A subscribed process group changed ProcessGroupChanged(crate::pg::GroupChangeMessage), @@ -110,8 +110,8 @@ impl SupervisionEvent { pub(crate) fn clone_no_data(&self) -> Self { match self { Self::ActorStarted(who) => Self::ActorStarted(who.clone()), - Self::ActorPanicked(who, what) => { - Self::ActorPanicked(who.clone(), From::from(format!("{what}"))) + Self::ActorFailed(who, what) => { + Self::ActorFailed(who.clone(), From::from(format!("{what}"))) } Self::ProcessGroupChanged(what) => Self::ProcessGroupChanged(what.clone()), Self::ActorTerminated(who, _state, msg) => { @@ -131,7 +131,7 @@ impl SupervisionEvent { pub fn actor_cell(&self) -> Option<&super::actor_cell::ActorCell> { match self { Self::ActorStarted(who) - | Self::ActorPanicked(who, _) + | Self::ActorFailed(who, _) | Self::ActorTerminated(who, _, _) => Some(who), _ => None, } @@ -166,7 +166,7 @@ impl std::fmt::Display for SupervisionEvent { write!(f, "Stopped actor {actor:?}") } } - SupervisionEvent::ActorPanicked(actor, panic_msg) => { + SupervisionEvent::ActorFailed(actor, panic_msg) => { write!(f, "Actor panicked {actor:?} - {panic_msg}") } SupervisionEvent::ProcessGroupChanged(change) => { diff --git a/ractor/src/actor/mod.rs b/ractor/src/actor/mod.rs index d0cfd131..c8551e75 100644 --- a/ractor/src/actor/mod.rs +++ b/ractor/src/actor/mod.rs @@ -315,7 +315,7 @@ pub trait Actor: Sized + Sync + Send + 'static { async move { match message { SupervisionEvent::ActorTerminated(who, _, _) - | SupervisionEvent::ActorPanicked(who, _) => { + | SupervisionEvent::ActorFailed(who, _) => { myself.stop(None); } _ => {} @@ -340,7 +340,7 @@ pub trait Actor: Sized + Sync + Send + 'static { ) -> Result<(), ActorProcessingErr> { match message { SupervisionEvent::ActorTerminated(who, _, _) - | SupervisionEvent::ActorPanicked(who, _) => { + | SupervisionEvent::ActorFailed(who, _) => { myself.stop(None); } _ => {} @@ -620,7 +620,7 @@ where supervisor: ActorCell, ) -> Result<(ActorRef, JoinHandle<()>), SpawnErr> { if id.is_local() { - Err(SpawnErr::StartupPanic(From::from( + Err(SpawnErr::StartupFailed(From::from( "Cannot spawn a remote actor when the identifier is not remote!", ))) } else { @@ -697,7 +697,7 @@ where // Perform the pre-start routine, crashing immediately if we fail to start let mut state = Self::do_pre_start(actor_ref.clone(), &handler, startup_args) .await? - .map_err(SpawnErr::StartupPanic)?; + .map_err(SpawnErr::StartupFailed)?; // setup supervision if let Some(sup) = &supervisor { @@ -724,7 +724,7 @@ where None, Some("killed".to_string()), ), - ActorErr::Panic(msg) => SupervisionEvent::ActorPanicked(myself.get_cell(), msg), + ActorErr::Failed(msg) => SupervisionEvent::ActorFailed(myself.get_cell(), msg), }, }; @@ -761,7 +761,7 @@ where // perform the post-start, with supervision enabled Self::do_post_start(myself.clone(), handler, state) .await? - .map_err(ActorErr::Panic)?; + .map_err(ActorErr::Failed)?; myself.set_status(ActorStatus::Running); myself.notify_supervisor_and_monitors(SupervisionEvent::ActorStarted(myself.get_cell())); @@ -778,7 +778,7 @@ where was_killed, } = Self::process_message(myself.clone(), state, handler, &mut ports) .await - .map_err(ActorErr::Panic)?; + .map_err(ActorErr::Failed)?; // processing loop exit if should_exit { return Ok((state, exit_reason, was_killed)); @@ -788,7 +788,7 @@ where // capture any panics in this future and convert to an ActorErr let loop_done = futures::FutureExt::catch_unwind(AssertUnwindSafe(future)) - .map_err(|err| ActorErr::Panic(get_panic_string(err))) + .map_err(|err| ActorErr::Failed(get_panic_string(err))) .await; // set status to stopping @@ -800,7 +800,7 @@ where if !was_killed { Self::do_post_stop(myself_clone, handler, exit_state) .await? - .map_err(ActorErr::Panic)?; + .map_err(ActorErr::Failed)?; } Ok(exit_reason) @@ -955,7 +955,7 @@ where let future = handler.pre_start(myself, arguments); futures::FutureExt::catch_unwind(AssertUnwindSafe(future)) .await - .map_err(|err| SpawnErr::StartupPanic(get_panic_string(err))) + .map_err(|err| SpawnErr::StartupFailed(get_panic_string(err))) } async fn do_post_start( @@ -966,7 +966,7 @@ where let future = handler.post_start(myself, state); futures::FutureExt::catch_unwind(AssertUnwindSafe(future)) .await - .map_err(|err| ActorErr::Panic(get_panic_string(err))) + .map_err(|err| ActorErr::Failed(get_panic_string(err))) } async fn do_post_stop( @@ -977,6 +977,6 @@ where let future = handler.post_stop(myself, state); futures::FutureExt::catch_unwind(AssertUnwindSafe(future)) .await - .map_err(|err| ActorErr::Panic(get_panic_string(err))) + .map_err(|err| ActorErr::Failed(get_panic_string(err))) } } diff --git a/ractor/src/actor/tests/mod.rs b/ractor/src/actor/tests/mod.rs index 18708cd6..33a2fe79 100644 --- a/ractor/src/actor/tests/mod.rs +++ b/ractor/src/actor/tests/mod.rs @@ -43,7 +43,7 @@ async fn test_panic_on_start_captured() { } let actor_output = Actor::spawn(None, TestActor, ()).await; - assert!(matches!(actor_output, Err(SpawnErr::StartupPanic(_)))); + assert!(matches!(actor_output, Err(SpawnErr::StartupFailed(_)))); } #[crate::concurrency::test] @@ -67,7 +67,7 @@ async fn test_error_on_start_captured() { } let actor_output = Actor::spawn(None, TestActor, ()).await; - assert!(matches!(actor_output, Err(SpawnErr::StartupPanic(_)))); + assert!(matches!(actor_output, Err(SpawnErr::StartupFailed(_)))); } #[crate::concurrency::test] @@ -935,7 +935,7 @@ fn returns_actor_references() { (true, SupervisionEvent::ActorStarted(dummy_actor_cell())), ( true, - SupervisionEvent::ActorPanicked(dummy_actor_cell(), "Bang!".into()), + SupervisionEvent::ActorFailed(dummy_actor_cell(), "Bang!".into()), ), ( true, diff --git a/ractor/src/actor/tests/supervisor.rs b/ractor/src/actor/tests/supervisor.rs index 56567cd0..c791644b 100644 --- a/ractor/src/actor/tests/supervisor.rs +++ b/ractor/src/actor/tests/supervisor.rs @@ -76,7 +76,7 @@ async fn test_supervision_panic_in_post_startup() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -164,7 +164,7 @@ async fn test_supervision_error_in_post_startup() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -253,7 +253,7 @@ async fn test_supervision_panic_in_handle() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -350,7 +350,7 @@ async fn test_supervision_error_in_handle() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -439,7 +439,7 @@ async fn test_supervision_panic_in_post_stop() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -520,7 +520,7 @@ async fn test_supervision_error_in_post_stop() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -600,7 +600,7 @@ async fn test_supervision_panic_in_supervisor_handle() { _message: SupervisionEvent, _state: &mut Self::State, ) -> Result<(), ActorProcessingErr> { - if let SupervisionEvent::ActorPanicked(_child, _msg) = _message { + if let SupervisionEvent::ActorFailed(_child, _msg) = _message { panic!("Boom again!"); } Ok(()) @@ -637,7 +637,7 @@ async fn test_supervision_panic_in_supervisor_handle() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); @@ -742,7 +742,7 @@ async fn test_supervision_error_in_supervisor_handle() { _message: SupervisionEvent, _state: &mut Self::State, ) -> Result<(), ActorProcessingErr> { - if let SupervisionEvent::ActorPanicked(_child, _msg) = _message { + if let SupervisionEvent::ActorFailed(_child, _msg) = _message { return Err(From::from("boom again!")); } Ok(()) @@ -779,7 +779,7 @@ async fn test_supervision_error_in_supervisor_handle() { println!("Supervisor event received {message:?}"); // check that the panic was captured - if let SupervisionEvent::ActorPanicked(dead_actor, _panic_msg) = message { + if let SupervisionEvent::ActorFailed(dead_actor, _panic_msg) = message { self.flag .store(dead_actor.get_id().pid(), Ordering::Relaxed); this_actor.stop(None); diff --git a/ractor/src/errors.rs b/ractor/src/errors.rs index f6ba5ba5..69bf1be5 100644 --- a/ractor/src/errors.rs +++ b/ractor/src/errors.rs @@ -13,12 +13,10 @@ use crate::ActorName; pub type ActorProcessingErr = Box; /// Spawn errors starting an actor -#[derive(Debug)] // TODO: why Eq, PartialEq? +#[derive(Debug)] pub enum SpawnErr { - /// Actor panic'd during startup - StartupPanic(ActorProcessingErr), - /// Actor failed to startup because the startup task was cancelled - StartupCancelled, + /// Actor panic'd or returned an error during startup + StartupFailed(ActorProcessingErr), /// An actor cannot be started > 1 time ActorAlreadyStarted, /// The named actor is already registered in the registry @@ -28,7 +26,7 @@ pub enum SpawnErr { impl std::error::Error for SpawnErr { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::StartupPanic(inner) => Some(inner.as_ref()), + Self::StartupFailed(inner) => Some(inner.as_ref()), _ => None, } } @@ -37,19 +35,13 @@ impl std::error::Error for SpawnErr { impl Display for SpawnErr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::StartupPanic(panic_msg) => { + Self::StartupFailed(panic_msg) => { if f.alternate() { write!(f, "Actor panicked during startup '{panic_msg:#}'") } else { write!(f, "Actor panicked during startup '{panic_msg}'") } } - Self::StartupCancelled => { - write!( - f, - "Actor failed to startup due to processing task being cancelled" - ) - } Self::ActorAlreadyStarted => { write!(f, "Actor cannot be re-started more than once") } @@ -79,13 +71,13 @@ pub enum ActorErr { /// Actor had a task cancelled internally during processing Cancelled, /// Actor had an internal panic - Panic(ActorProcessingErr), + Failed(ActorProcessingErr), } impl std::error::Error for ActorErr { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::Panic(inner) => Some(inner.as_ref()), + Self::Failed(inner) => Some(inner.as_ref()), _ => None, } } @@ -94,7 +86,7 @@ impl std::error::Error for ActorErr { impl Display for ActorErr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Panic(panic_msg) => { + Self::Failed(panic_msg) => { if f.alternate() { write!(f, "Actor panicked '{panic_msg:#}'") } else { diff --git a/ractor/src/factory/factoryimpl.rs b/ractor/src/factory/factoryimpl.rs index b106e605..cd4e0363 100644 --- a/ractor/src/factory/factoryimpl.rs +++ b/ractor/src/factory/factoryimpl.rs @@ -931,7 +931,7 @@ where state.try_route_next_active_job(wid)?; } } - SupervisionEvent::ActorPanicked(who, reason) => { + SupervisionEvent::ActorFailed(who, reason) => { let wid = if let Some(worker) = state .pool .values_mut() diff --git a/ractor/src/lib.rs b/ractor/src/lib.rs index bedf8179..78c0967e 100644 --- a/ractor/src/lib.rs +++ b/ractor/src/lib.rs @@ -12,7 +12,7 @@ //! //! ```toml //! [dependencies] -//! ractor = "0.9" +//! ractor = "0.10" //! ``` //! //! The minimum supported Rust version (MSRV) is 1.64. However if you disable the `async-trait` feature, then you need Rust >= 1.75 due to the native diff --git a/ractor/src/tests.rs b/ractor/src/tests.rs index cfc5c789..06c919b4 100644 --- a/ractor/src/tests.rs +++ b/ractor/src/tests.rs @@ -15,10 +15,6 @@ use crate::RactorErr; #[test] #[tracing_test::traced_test] fn test_error_conversions() { - let spawn = crate::SpawnErr::StartupCancelled; - let ractor_err = RactorErr::<()>::from(crate::SpawnErr::StartupCancelled); - assert_eq!(spawn.to_string(), ractor_err.to_string()); - let messaging = crate::MessagingErr::<()>::InvalidActorType; let ractor_err = RactorErr::<()>::from(crate::MessagingErr::InvalidActorType); assert_eq!(messaging.to_string(), ractor_err.to_string()); diff --git a/ractor_cluster/src/net/session.rs b/ractor_cluster/src/net/session.rs index 0386f2c6..9b91f7aa 100644 --- a/ractor_cluster/src/net/session.rs +++ b/ractor_cluster/src/net/session.rs @@ -203,7 +203,7 @@ impl Actor for Session { // sockets open, they close, the world goes round... If a reader or writer exits for any reason, we'll start the shutdown procedure // which requires that all actors exit match message { - SupervisionEvent::ActorPanicked(actor, panic_msg) => { + SupervisionEvent::ActorFailed(actor, panic_msg) => { if actor.get_id() == state.reader.get_id() { tracing::error!("TCP Session's reader panicked with '{panic_msg}'"); } else if actor.get_id() == state.writer.get_id() { diff --git a/ractor_cluster/src/node/mod.rs b/ractor_cluster/src/node/mod.rs index 9485bd8d..aaa110cd 100644 --- a/ractor_cluster/src/node/mod.rs +++ b/ractor_cluster/src/node/mod.rs @@ -430,7 +430,7 @@ impl Actor for NodeServer { state: &mut Self::State, ) -> Result<(), ActorProcessingErr> { match message { - SupervisionEvent::ActorPanicked(actor, msg) => { + SupervisionEvent::ActorFailed(actor, msg) => { if state.listener.get_id() == actor.get_id() { tracing::error!( "The Node server's TCP listener failed with '{msg}'. Respawning!" diff --git a/ractor_cluster/src/node/node_session/mod.rs b/ractor_cluster/src/node/node_session/mod.rs index 0c80421f..c3575d9b 100644 --- a/ractor_cluster/src/node/node_session/mod.rs +++ b/ractor_cluster/src/node/node_session/mod.rs @@ -956,7 +956,7 @@ impl Actor for NodeSession { ) -> Result<(), ActorProcessingErr> { match message { SupervisionEvent::ActorStarted(_) => {} - SupervisionEvent::ActorPanicked(actor, msg) => { + SupervisionEvent::ActorFailed(actor, msg) => { if state.is_tcp_actor(actor.get_id()) { tracing::error!( "Node session {:?}'s TCP session panicked with '{msg}'",