1+ //! This needs to be its own crate so that it doesn't pull in anything that would make compiling
2+ //! to WASM not work. I've already figured out how to do all that once before with my WASM workflows
3+ //! hackathon
4+
15use futures:: future:: BoxFuture ;
2- use std:: { error:: Error , time:: Duration } ;
3- use temporal_sdk_core_protos:: temporal:: api:: common:: v1:: Payload ;
6+ use std:: time:: Duration ;
7+ use temporal_sdk_core_protos:: {
8+ coresdk:: workflow_commands:: ContinueAsNewWorkflowExecution , temporal:: api:: common:: v1:: Payload ,
9+ } ;
10+
11+ // anyhow errors are used for the errors returned by user-defined functions. This makes `?` work
12+ // well everywhere by default which is a very nice property, as well as preserving backtraces. We
13+ // may need to define our own error type instead to allow attaching things like the non-retryable
14+ // flag... but I suspect we can just make downcasting work for that.
415
516/// Workflow authors must implement this trait to create Temporal Rust workflows
617pub trait Workflow : Sized {
@@ -22,7 +33,10 @@ pub trait Workflow: Sized {
2233 ///
2334 /// `ctx` should be used to perform various Temporal commands like starting timers and
2435 /// activities.
25- fn run ( & mut self , ctx : WfContext ) -> BoxFuture < Self :: Output > ;
36+ fn run (
37+ & mut self ,
38+ ctx : WfContext ,
39+ ) -> BoxFuture < Result < WfExitValue < Self :: Output > , anyhow:: Error > > ;
2640
2741 /// All signals this workflow can handle. Typically you won't implement this directly, it will
2842 /// automatically contain all signals defined with the `#[signal]` attribute.
@@ -38,13 +52,30 @@ pub trait Workflow: Sized {
3852 }
3953}
4054
55+ /// TODO: Exists in SDK in slightly different form, and would move into this crate
56+ #[ derive( Debug ) ]
57+ pub enum WfExitValue < T : TemporalSerializable > {
58+ /// Continue the workflow as a new execution
59+ ContinueAsNew ( Box < ContinueAsNewWorkflowExecution > ) , // Wouldn't be raw proto in reality
60+ /// Confirm the workflow was cancelled
61+ Cancelled ,
62+ /// Finish with a result
63+ Normal ( T ) ,
64+ }
65+ impl < T : TemporalSerializable > From < T > for WfExitValue < T > {
66+ fn from ( v : T ) -> Self {
67+ Self :: Normal ( v)
68+ }
69+ }
70+ // ... also convenience functions for constructing C-A-N, etc.
71+
4172/// A workflow context which contains only information, but does not allow any commands to
4273/// be created.
4374pub struct SafeWfContext {
4475 // TODO
4576}
4677
47- /// TODO: Placeholder, move from SDK
78+ /// TODO: Placeholder, exists in SDK and would move into this crate & (likely) become a trait
4879pub struct WfContext { }
4980impl WfContext {
5081 pub async fn timer ( & self , _: Duration ) {
@@ -53,26 +84,25 @@ impl WfContext {
5384}
5485
5586pub struct SignalDefinition < WF : Workflow > {
56- // TODO: Could be a matching predicate
87+ // TODO: Could be a matching predicate, to allow for dynamic registration
5788 name : String ,
5889 // The handler input type must be erased here, since otherwise we couldn't store/return the
5990 // heterogeneous collection of definition types in the workflow itself. The signal macro
60- // will wrap the user's function with code that performs deserialization, as well as error
61- // boxing.
62- handler : Box < dyn FnMut ( & mut WF , Payload ) -> Result < ( ) , Box < dyn Error > > > ,
91+ // will wrap the user's function with code that performs deserialization.
92+ handler : Box < dyn FnMut ( & mut WF , Payload ) -> Result < ( ) , anyhow:: Error > > ,
6393}
6494pub struct QueryDefinition < WF : Workflow > {
65- // TODO: Could be a matching predicate
95+ // TODO: Could be a matching predicate, to allow for dynamic registration
6696 name : String ,
6797 // The query macro will wrap the user's function with code that performs deserialization of
6898 // input and serialization of output, as well as error boxing.
69- handler : Box < dyn FnMut ( & WF , Payload ) -> Result < Payload , Box < dyn Error > > > ,
99+ handler : Box < dyn FnMut ( & WF , Payload ) -> Result < Payload , anyhow :: Error > > ,
70100}
71101
72- /// TODO: Placeholder, move from (and improve in) SDK
102+ /// TODO: Placeholders, likely belong inside protos crate. These will be auto-implemented for
103+ /// anything using serde already (which I expect is how virtually everyone will do this).
73104pub trait TemporalSerializable { }
74105impl < T > TemporalSerializable for T { }
75- /// TODO: Placeholder, move from (and improve in) SDK
76106pub trait TemporalDeserializable { }
77107impl < T > TemporalDeserializable for T { }
78108
@@ -99,11 +129,18 @@ mod tests {
99129 Self { foo : 0 , bar }
100130 }
101131
102- fn run ( & mut self , ctx : WfContext ) -> BoxFuture < Self :: Output > {
132+ fn run (
133+ & mut self ,
134+ ctx : WfContext ,
135+ ) -> BoxFuture < Result < WfExitValue < Self :: Output > , anyhow:: Error > > {
103136 async move {
104137 ctx. timer ( Duration :: from_secs ( 1 ) ) . await ;
105138 self . foo = 1 ;
106- self . foo
139+ // The into() is unfortunately unavoidable without making C-A-N and confirm cancel
140+ // be errors instead. Personally, I don't love that and I think it's not idiomatic
141+ // Rust, whereas needing to `into()` something is. Other way would be macros, but
142+ // it's slightly too much magic I think.
143+ Ok ( self . foo . into ( ) )
107144 }
108145 . boxed ( )
109146 // TODO: The need to box here is slightly unfortunate, but it's either that or require
@@ -114,7 +151,7 @@ mod tests {
114151
115152 // #[workflow] miiiight be necessary here, but, ideally is not.
116153 impl MyWorkflow {
117- // Attrib commented out since nonexistent for now, but that's what it'd look like.
154+ // Attrib commented out since it's nonexistent for now, but that's what it'd look like.
118155 // #[signal]
119156 pub fn my_signal ( & mut self , arg : String ) {
120157 self . bar . insert ( arg, 1 ) ;
@@ -139,7 +176,7 @@ mod tests {
139176 }
140177 impl MyWorkflowClientExtension for WorkflowHandle < MyWorkflow > {
141178 fn my_signal ( & self , arg : String ) -> BoxFuture < Result < ( ) , SignalError > > {
142- // Is actually something like:
179+ // Becomes something like:
143180 // self.signal("my_signal", arg.serialize())
144181 todo ! ( )
145182 }
@@ -157,4 +194,7 @@ mod tests {
157194 } ;
158195 let _ = wfh. my_signal ( "hi!" . to_string ( ) ) . await ;
159196 }
197+
198+ #[ test]
199+ fn compile ( ) { }
160200}
0 commit comments