From dbbbc8c1c6a43921a198ada2bf221d2234fe7d02 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 30 Jan 2023 14:25:58 +0100 Subject: [PATCH] Breaking change: much improved error API --- syndicate-macros/examples/box-and-client.rs | 2 +- syndicate-server/examples/consumer.rs | 2 +- syndicate-server/examples/pingpong.rs | 2 +- syndicate-server/examples/producer.rs | 2 +- syndicate-server/examples/state-consumer.rs | 2 +- syndicate-server/examples/state-producer.rs | 2 +- syndicate-server/src/main.rs | 2 +- syndicate-server/src/protocol.rs | 2 +- syndicate/src/actor.rs | 36 ++++++++++++--------- syndicate/src/during.rs | 14 ++++---- syndicate/src/error.rs | 18 +++++++++++ syndicate/src/lib.rs | 2 +- syndicate/src/relay.rs | 8 ++--- 13 files changed, 59 insertions(+), 35 deletions(-) diff --git a/syndicate-macros/examples/box-and-client.rs b/syndicate-macros/examples/box-and-client.rs index fcbb4cc..4653c03 100644 --- a/syndicate-macros/examples/box-and-client.rs +++ b/syndicate-macros/examples/box-and-client.rs @@ -6,7 +6,7 @@ use syndicate::schemas::dataspace::Observe; use syndicate::value::NestedValue; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; Actor::top(None, |t| { let ds = Cap::new(&t.create(Dataspace::new(None))); diff --git a/syndicate-server/examples/consumer.rs b/syndicate-server/examples/consumer.rs index d4093cf..d0296be 100644 --- a/syndicate-server/examples/consumer.rs +++ b/syndicate-server/examples/consumer.rs @@ -20,7 +20,7 @@ pub struct Config { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; let config = Config::from_args(); let sturdyref = sturdy::SturdyRef::from_hex(&config.dataspace)?; diff --git a/syndicate-server/examples/pingpong.rs b/syndicate-server/examples/pingpong.rs index 3dc0a37..e0491e0 100644 --- a/syndicate-server/examples/pingpong.rs +++ b/syndicate-server/examples/pingpong.rs @@ -89,7 +89,7 @@ fn report_latencies(rtt_ns_samples: &Vec) { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; let config = Config::from_args(); let sturdyref = sturdy::SturdyRef::from_hex(&config.dataspace)?; diff --git a/syndicate-server/examples/producer.rs b/syndicate-server/examples/producer.rs index 353b20a..3db2a57 100644 --- a/syndicate-server/examples/producer.rs +++ b/syndicate-server/examples/producer.rs @@ -21,7 +21,7 @@ pub struct Config { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; let config = Config::from_args(); let sturdyref = sturdy::SturdyRef::from_hex(&config.dataspace)?; diff --git a/syndicate-server/examples/state-consumer.rs b/syndicate-server/examples/state-consumer.rs index 6a0cd5d..5c78263 100644 --- a/syndicate-server/examples/state-consumer.rs +++ b/syndicate-server/examples/state-consumer.rs @@ -20,7 +20,7 @@ pub struct Config { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; let config = Config::from_args(); let sturdyref = sturdy::SturdyRef::from_hex(&config.dataspace)?; diff --git a/syndicate-server/examples/state-producer.rs b/syndicate-server/examples/state-producer.rs index 8861e5e..5052e13 100644 --- a/syndicate-server/examples/state-producer.rs +++ b/syndicate-server/examples/state-producer.rs @@ -15,7 +15,7 @@ pub struct Config { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { syndicate::convenient_logging()?; let config = Config::from_args(); let sturdyref = sturdy::SturdyRef::from_hex(&config.dataspace)?; diff --git a/syndicate-server/src/main.rs b/syndicate-server/src/main.rs index df8b9c0..73a17e1 100644 --- a/syndicate-server/src/main.rs +++ b/syndicate-server/src/main.rs @@ -59,7 +59,7 @@ struct ServerConfig { } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> ActorResult { let config = Arc::new(ServerConfig::from_args()); syndicate::convenient_logging()?; diff --git a/syndicate-server/src/protocol.rs b/syndicate-server/src/protocol.rs index d6ae3d3..71add82 100644 --- a/syndicate-server/src/protocol.rs +++ b/syndicate-server/src/protocol.rs @@ -19,7 +19,7 @@ use tungstenite::Message; struct ExitListener; impl Entity<()> for ExitListener { - fn exit_hook(&mut self, _t: &mut Activation, exit_status: &Arc) { + fn exit_hook(&mut self, _t: &mut Activation, exit_status: &Arc) { tracing::info!(?exit_status, "disconnect"); } } diff --git a/syndicate/src/actor.rs b/syndicate/src/actor.rs index dcb45a4..81b0933 100644 --- a/syndicate/src/actor.rs +++ b/syndicate/src/actor.rs @@ -82,8 +82,14 @@ pub type FieldId = NonZeroU64; /// The type of process-unique field observer block IDs. pub type BlockId = NonZeroU64; +/// Error responses to events must have type `ActorError`. +pub type ActorError = Box; + /// Responses to events must have type `ActorResult`. -pub type ActorResult = Result<(), Error>; +pub type ActorResult = Result<(), ActorError>; + +/// Final exit status of an actor. +pub type ExitStatus = Result<(), Error>; /// The [`Actor::boot`] method returns an `ActorHandle`, representing /// the actor's mainloop task. @@ -207,7 +213,7 @@ pub trait Entity: Send { /// [RunningActor::add_exit_hook]. /// /// The default implementation does nothing. - fn exit_hook(&mut self, turn: &mut Activation, exit_status: &Arc) { + fn exit_hook(&mut self, turn: &mut Activation, exit_status: &Arc) { } } @@ -352,7 +358,7 @@ pub enum ActorState { Terminated { /// The exit status of the actor: `Ok(())` for normal /// termination, `Err(_)` for abnormal termination. - exit_status: Arc, + exit_status: Arc, }, } @@ -368,7 +374,7 @@ pub struct RunningActor { #[doc(hidden)] pub fields: HashMap>, blocks: HashMap, - exit_hooks: Vec)>>, + exit_hooks: Vec)>>, #[doc(hidden)] pub outbound_assertions: OutboundAssertions, #[doc(hidden)] @@ -665,7 +671,7 @@ impl FacetRef { match maybe_exit_status { None => true, Some(exit_status) => { - g.terminate(exit_status, &self.actor, &account.trace_collector); + g.terminate(exit_status.map_err(|e| e.into()), &self.actor, &account.trace_collector); false } } @@ -1253,7 +1259,7 @@ impl<'activation> Activation<'activation> { pub fn facet ActorResult>( &mut self, boot: F, - ) -> Result { + ) -> Result { let f = Facet::new(Some(self.facet.facet_id)); self.trace(|t| trace::ActionDescription::FacetStart { path: t.facet_ids_for(&f).iter().map(|i| trace::FacetId(AnyValue::new(u64::from(*i)))).collect(), @@ -1502,7 +1508,7 @@ impl<'activation> Activation<'activation> { Ok(()) } - fn repair_dataflow(&mut self) -> Result { + fn repair_dataflow(&mut self) -> Result { let mut pass_number = 0; while !self.state.dataflow.is_clean() { pass_number += 1; @@ -1688,8 +1694,8 @@ fn send_actions( t: PendingEventQueue, ) -> ActorResult { let token_count = t.len(); - tx.send(SystemMessage::Turn(caused_by, LoanedItem::new(account, token_count, t))) - .map_err(|_| error("Target actor not running", AnyValue::new(false))) + Ok(tx.send(SystemMessage::Turn(caused_by, LoanedItem::new(account, token_count, t))) + .map_err(|_| error("Target actor not running", AnyValue::new(false)))?) } impl std::fmt::Debug for Mailbox { @@ -1836,7 +1842,7 @@ impl Actor { let root_facet_ref = self.ac_ref.root_facet_ref(); let terminate = |e: Error | { - assert!(!root_facet_ref.activate(&Account::new(None, None), None, |_| Err(e))); + assert!(!root_facet_ref.activate(&Account::new(None, None), None, |_| Err(e)?)); }; if !root_facet_ref.activate(&boot_account, boot_cause, boot) { @@ -1940,7 +1946,7 @@ impl ActorRef { pub fn exit_status(&self) -> Option { self.access(|state| match state { ActorState::Running(_) => None, - ActorState::Terminated { exit_status } => Some((**exit_status).clone()), + ActorState::Terminated { exit_status } => Some((**exit_status).clone().map_err(|e| e.into())), }) } @@ -1979,7 +1985,7 @@ impl ActorState { fn terminate( &mut self, - exit_status: ActorResult, + exit_status: ExitStatus, actor: &ActorRef, trace_collector: &Option, ) { @@ -2076,7 +2082,7 @@ impl RunningActor { fn cleanup( mut self, ac_ref: &ActorRef, - exit_status: Arc, + exit_status: Arc, trace_collector: Option, ) { if exit_status.is_ok() { @@ -2250,7 +2256,7 @@ impl Cap { Self::new(&Arc::new(Ref { mailbox: Arc::clone(&underlying.mailbox), facet_id: underlying.facet_id, - target: Mutex::new(Some(Box::new(Guard { underlying: underlying, literals }))), + target: Mutex::new(Some(Box::new(Guard { underlying, literals }))), })) } @@ -2378,7 +2384,7 @@ where fn stop(&mut self, t: &mut Activation) -> ActorResult { t.with_entity(&self.underlying, |t, e| e.stop(t)) } - fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { + fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { self.underlying.internal_with_entity(|e| e.exit_hook(t, exit_status)) } } diff --git a/syndicate/src/during.rs b/syndicate/src/during.rs index 87b4639..8cc58f3 100644 --- a/syndicate/src/during.rs +++ b/syndicate/src/during.rs @@ -17,7 +17,7 @@ where Fa: 'static + Send + FnMut(&mut E, &mut Activation, M) -> DuringResult, Fm: 'static + Send + FnMut(&mut E, &mut Activation, M) -> ActorResult, Fs: 'static + Send + FnMut(&mut E, &mut Activation) -> ActorResult, - Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), + Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), { state: E, assertion_handler: Option, @@ -54,7 +54,7 @@ pub fn entity( fn (&mut E, &mut Activation, M) -> DuringResult, fn (&mut E, &mut Activation, M) -> ActorResult, fn (&mut E, &mut Activation) -> ActorResult, - fn (&mut E, &mut Activation, &Arc)> + fn (&mut E, &mut Activation, &Arc)> where E: 'static + Send, { @@ -68,7 +68,7 @@ where Fa: 'static + Send + FnMut(&mut E, &mut Activation, M) -> DuringResult, Fm: 'static + Send + FnMut(&mut E, &mut Activation, M) -> ActorResult, Fs: 'static + Send + FnMut(&mut E, &mut Activation) -> ActorResult, - Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), + Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), { pub fn new( state: E, @@ -154,7 +154,7 @@ where pub fn on_exit(self, exit_handler: Fx1) -> DuringEntity where - Fx1: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), + Fx1: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), { DuringEntity { state: self.state, @@ -187,7 +187,7 @@ where Fa: 'static + Send + FnMut(&mut E, &mut Activation, AnyValue) -> DuringResult, Fm: 'static + Send + FnMut(&mut E, &mut Activation, AnyValue) -> ActorResult, Fs: 'static + Send + FnMut(&mut E, &mut Activation) -> ActorResult, - Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), + Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), { pub fn create_cap(self, t: &mut Activation) -> Arc { @@ -202,7 +202,7 @@ where Fa: 'static + Send + FnMut(&mut E, &mut Activation, M) -> DuringResult, Fm: 'static + Send + FnMut(&mut E, &mut Activation, M) -> ActorResult, Fs: 'static + Send + FnMut(&mut E, &mut Activation) -> ActorResult, - Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), + Fx: 'static + Send + FnMut(&mut E, &mut Activation, &Arc), { fn assert(&mut self, t: &mut Activation, a: M, h: Handle) -> ActorResult { match &mut self.assertion_handler { @@ -232,7 +232,7 @@ where } } - fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { + fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { if let Some(handler) = &mut self.exit_handler { handler(&mut self.state, t, exit_status); } diff --git a/syndicate/src/error.rs b/syndicate/src/error.rs index ecc7111..0340c09 100644 --- a/syndicate/src/error.rs +++ b/syndicate/src/error.rs @@ -73,3 +73,21 @@ impl From for Error { error(&format!("{}", v), AnyValue::new(false)) } } + +impl From> for Error { + fn from(v: Box) -> Self { + match v.downcast::() { + Ok(e) => *e, + Err(v) => error(&format!("{}", v), AnyValue::new(false)), + } + } +} + +impl From> for Error { + fn from(v: Box) -> Self { + match v.downcast::() { + Ok(e) => *e, + Err(v) => error(&format!("{}", v), AnyValue::new(false)), + } + } +} diff --git a/syndicate/src/lib.rs b/syndicate/src/lib.rs index 0a945ce..1eb2f45 100644 --- a/syndicate/src/lib.rs +++ b/syndicate/src/lib.rs @@ -38,7 +38,7 @@ pub use during::entity; /// Sets up [`tracing`] logging in a reasonable way. /// /// Useful at the top of `main` functions. -pub fn convenient_logging() -> Result<(), Box> { +pub fn convenient_logging() -> actor::ActorResult { let filter = match std::env::var(tracing_subscriber::filter::EnvFilter::DEFAULT_ENV) { Err(std::env::VarError::NotPresent) => tracing_subscriber::filter::EnvFilter::default() diff --git a/syndicate/src/relay.rs b/syndicate/src/relay.rs index ac0bcfd..30cabcb 100644 --- a/syndicate/src/relay.rs +++ b/syndicate/src/relay.rs @@ -313,7 +313,7 @@ impl TunnelRelay { tracing::info!(message = ?b.message.clone(), detail = ?b.detail.clone(), "received Error from peer"); - Err(*b) + Err(*b)? } P::Packet::Turn(b) => { let P::Turn(events) = *b; @@ -338,7 +338,7 @@ impl TunnelRelay { &mut |r| Ok(pins.push(self.membranes.lookup_ref(r))))?; if let Some(local_handle) = target.assert(t, &(), &a) { if let Some(_) = self.inbound_assertions.insert(remote_handle, (local_handle, pins)) { - return Err(error("Assertion with duplicate handle", AnyValue::new(false))); + return Err(error("Assertion with duplicate handle", AnyValue::new(false)))?; } } else { self.membranes.release(pins); @@ -348,7 +348,7 @@ impl TunnelRelay { P::Event::Retract(b) => { let P::Retract { handle: remote_handle } = *b; let (local_handle, previous_pins) = match self.inbound_assertions.remove(&remote_handle) { - None => return Err(error("Retraction of nonexistent handle", language().unparse(&remote_handle))), + None => return Err(error("Retraction of nonexistent handle", language().unparse(&remote_handle)))?, Some(wss) => wss, }; self.membranes.release(previous_pins); @@ -715,7 +715,7 @@ async fn output_loop( } impl Entity<()> for TunnelRefEntity { - fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { + fn exit_hook(&mut self, t: &mut Activation, exit_status: &Arc) { if let Err(e) = &**exit_status { let e = e.clone(); let mut g = self.relay_ref.lock();