diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index ccf8b06b8..a0f49ae41 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -47,6 +47,7 @@ extern crate tracing; mod activity_context; mod app_data; pub mod interceptors; +pub mod new_activity_defs; mod payload_converter; mod workflow_context; mod workflow_future; diff --git a/sdk/src/new_activity_defs.rs b/sdk/src/new_activity_defs.rs new file mode 100644 index 000000000..e69de29bb diff --git a/workflow-api/src/activity_definitions.rs b/workflow-api/src/activity_definitions.rs new file mode 100644 index 000000000..3d7e6936b --- /dev/null +++ b/workflow-api/src/activity_definitions.rs @@ -0,0 +1,43 @@ +use crate::WfContext; +use futures::future::BoxFuture; + +// #[activity_definition] +type MyActFn = fn(String) -> String; + +// Macro enforces types are serializable. + +// The biggest problem with activity definitions is they need to be defined in a crate which doesn't +// depend on the entire SDK, because then the workflow code which uses them wouldn't be able to +// be compiled down to WASM. Of course, the issue is activities _aren't_ compiled to WASM, and need +// access to full native functionality. Thus users need to structure their app a bit oddly. They +// can either define all their workflow code & activity _definitions_ in one crate, and then +// depend on that crate from another crate containing their activity implementations / worker, or +// they could make a crate with *just* activity definitions, which is depended on by the workflow +// implementation crate and the worker crate independently. It all makes perfect sense, but is +// maybe a bit annoying in terms of setup - though not really any worse than TS. + +// Macro generates this extension & implementation: +// +// The generated code taking `impl Into` is quite nice for ergonomics inside the workflow, +// but might be impossible in some cases, so probably macro would need a flag to turn it off. +pub trait MyActFnWfCtxExt { + // In reality this returns the `CancellableFuture` type from SDK, would also need to move into + // this crate. + fn my_act_fn( + &self, + input: impl Into, + ) -> BoxFuture<'static, Result>; +} +impl MyActFnWfCtxExt for WfContext { + fn my_act_fn(&self, _: impl Into) -> BoxFuture<'static, Result> { + // Type name is injected in this implementation, taken from macro + todo!() + } +} + +// To implement the activity in their implementation crate, the user would do something like: +// worker.register_activity(MyActFn, |input: String| async move { .... }); + +// Placeholder. Activity failures as can be seen by the WF code. +#[derive(Debug)] +pub struct ActivityFail {} diff --git a/workflow-api/src/lib.rs b/workflow-api/src/lib.rs index c5f31316b..58dc3d7b5 100644 --- a/workflow-api/src/lib.rs +++ b/workflow-api/src/lib.rs @@ -2,6 +2,9 @@ //! to WASM not work. I've already figured out how to do all that once before with my WASM workflows //! hackathon +mod activity_definitions; + +use activity_definitions::MyActFnWfCtxExt; use futures::future::BoxFuture; use std::time::Duration; use temporal_sdk_core_protos::{ @@ -136,6 +139,8 @@ mod tests { async move { ctx.timer(Duration::from_secs(1)).await; self.foo = 1; + // See activity definitions file + ctx.my_act_fn("Hi!").await.unwrap(); // The into() is unfortunately unavoidable without making C-A-N and confirm cancel // be errors instead. Personally, I don't love that and I think it's not idiomatic // Rust, whereas needing to `into()` something is. Other way would be macros, but