temporalio_workflow/runtime/
model.rs1use crate::{
4 runtime::types::ContinueAsNewRequest,
5 workflow_context::{
6 ChildWfCommon, NexusUnblockData, PendingChildWorkflow, StartedNexusOperation,
7 },
8};
9use temporalio_common_wasm::{
10 WorkflowDefinition,
11 error::{
12 ActivityExecutionError, ApplicationFailure, ChildWorkflowExecutionError,
13 WorkflowSignalError,
14 },
15 protos::{
16 coresdk::{
17 activity_result::ActivityResolution,
18 child_workflow::ChildWorkflowResult,
19 nexus::NexusOperationResult,
20 workflow_activation::{
21 resolve_child_workflow_execution_start::Status as ChildWorkflowStartStatus,
22 resolve_nexus_operation_start,
23 },
24 },
25 temporal::api::failure::v1::Failure,
26 },
27};
28
29#[derive(Debug)]
30pub enum UnblockEvent {
31 Timer(u32, TimerResult),
32 Activity(u32, Box<ActivityResolution>),
33 WorkflowStart(u32, Box<ChildWorkflowStartStatus>),
34 WorkflowComplete(u32, Box<ChildWorkflowResult>),
35 SignalExternal(u32, Option<Failure>),
36 CancelExternal(u32, Option<Failure>),
37 NexusOperationStart(u32, Box<resolve_nexus_operation_start::Status>),
38 NexusOperationComplete(u32, Box<NexusOperationResult>),
39}
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
43pub enum TimerResult {
44 Cancelled,
46 Fired,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub struct SignalExternalOk;
53pub type SignalExternalWfResult = Result<SignalExternalOk, Failure>;
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct CancelExternalOk;
59pub type CancelExternalWfResult = Result<CancelExternalOk, Failure>;
61
62pub(crate) trait Unblockable {
63 type OtherDat;
64
65 fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self;
66}
67
68impl Unblockable for TimerResult {
69 type OtherDat = ();
70
71 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
72 match ue {
73 UnblockEvent::Timer(_, result) => result,
74 _ => panic!("Invalid unblock event for timer"),
75 }
76 }
77}
78
79impl Unblockable for ActivityResolution {
80 type OtherDat = ();
81
82 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
83 match ue {
84 UnblockEvent::Activity(_, result) => *result,
85 _ => panic!("Invalid unblock event for activity"),
86 }
87 }
88}
89
90impl<WD: WorkflowDefinition> Unblockable for PendingChildWorkflow<WD> {
91 type OtherDat = ChildWfCommon;
92
93 fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self {
94 match ue {
95 UnblockEvent::WorkflowStart(_, result) => Self {
96 status: *result,
97 common: od,
98 _phantom: std::marker::PhantomData,
99 },
100 _ => panic!("Invalid unblock event for child workflow start"),
101 }
102 }
103}
104
105impl Unblockable for ChildWorkflowResult {
106 type OtherDat = ();
107
108 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
109 match ue {
110 UnblockEvent::WorkflowComplete(_, result) => *result,
111 _ => panic!("Invalid unblock event for child workflow complete"),
112 }
113 }
114}
115
116impl Unblockable for SignalExternalWfResult {
117 type OtherDat = ();
118
119 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
120 match ue {
121 UnblockEvent::SignalExternal(_, maybefail) => {
122 maybefail.map_or(Ok(SignalExternalOk), Err)
123 }
124 _ => panic!("Invalid unblock event for signal external workflow result"),
125 }
126 }
127}
128
129impl Unblockable for CancelExternalWfResult {
130 type OtherDat = ();
131
132 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
133 match ue {
134 UnblockEvent::CancelExternal(_, maybefail) => {
135 maybefail.map_or(Ok(CancelExternalOk), Err)
136 }
137 _ => panic!("Invalid unblock event for cancel external workflow result"),
138 }
139 }
140}
141
142pub(crate) type NexusStartResult = Result<StartedNexusOperation, Failure>;
143
144impl Unblockable for NexusStartResult {
145 type OtherDat = NexusUnblockData;
146
147 fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self {
148 let NexusUnblockData {
149 result_future,
150 schedule_seq,
151 base_ctx,
152 } = od;
153 match ue {
154 UnblockEvent::NexusOperationStart(_, result) => match *result {
155 resolve_nexus_operation_start::Status::OperationToken(op_token) => {
156 Ok(StartedNexusOperation {
157 operation_token: Some(op_token),
158 result_future,
159 schedule_seq,
160 base_ctx,
161 })
162 }
163 resolve_nexus_operation_start::Status::StartedSync(_) => {
164 Ok(StartedNexusOperation {
165 operation_token: None,
166 result_future,
167 schedule_seq,
168 base_ctx,
169 })
170 }
171 resolve_nexus_operation_start::Status::Failed(f) => Err(f),
172 },
173 _ => panic!("Invalid unblock event for nexus operation"),
174 }
175 }
176}
177
178impl Unblockable for NexusOperationResult {
179 type OtherDat = ();
180
181 fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
182 match ue {
183 UnblockEvent::NexusOperationComplete(_, result) => *result,
184 _ => panic!("Invalid unblock event for nexus operation complete"),
185 }
186 }
187}
188
189#[derive(Debug, Clone)]
190pub enum CancellableID {
191 Timer(u32),
192 Activity(u32),
193 LocalActivity(u32),
194 ChildWorkflow { seqnum: u32, reason: String },
195 SignalExternalWorkflow(u32),
196 NexusOp(u32),
197}
198
199impl CancellableID {
200 pub(crate) fn with_reason(self, reason: String) -> Self {
201 match self {
202 CancellableID::ChildWorkflow { seqnum, .. } => {
203 CancellableID::ChildWorkflow { seqnum, reason }
204 }
205 other => other,
206 }
207 }
208}
209
210pub type WorkflowResult<T> = Result<T, WorkflowTermination>;
212
213#[derive(Debug, thiserror::Error)]
215pub enum WorkflowTermination {
216 #[error("Workflow cancelled")]
217 Cancelled,
218 #[error("Workflow evicted from cache")]
219 Evicted,
220 #[error("Continue as new")]
221 ContinueAsNew(Box<ContinueAsNewRequest>),
222 #[error("Workflow failed: {0}")]
223 Failed(#[source] temporalio_common_wasm::error::OutgoingWorkflowError),
224}
225
226impl WorkflowTermination {
227 pub fn continue_as_new(can: ContinueAsNewRequest) -> Self {
228 Self::ContinueAsNew(Box::new(can))
229 }
230
231 pub fn failed_application(err: ApplicationFailure) -> Self {
233 Self::Failed(err.into())
234 }
235}
236
237impl From<anyhow::Error> for WorkflowTermination {
238 fn from(err: anyhow::Error) -> Self {
239 Self::Failed(err.into())
240 }
241}
242
243impl From<ApplicationFailure> for WorkflowTermination {
244 fn from(value: ApplicationFailure) -> Self {
245 Self::Failed(value.into())
246 }
247}
248
249impl From<temporalio_common_wasm::data_converters::PayloadConversionError> for WorkflowTermination {
250 fn from(value: temporalio_common_wasm::data_converters::PayloadConversionError) -> Self {
251 Self::Failed(value.into())
252 }
253}
254
255impl From<crate::runtime::entry::WorkflowError> for WorkflowTermination {
256 fn from(value: crate::runtime::entry::WorkflowError) -> Self {
257 match value {
258 crate::runtime::entry::WorkflowError::PayloadConversion(err) => Self::from(err),
259 crate::runtime::entry::WorkflowError::Execution(err) => Self::Failed(
260 temporalio_common_wasm::error::OutgoingWorkflowError::Application(Box::new(
261 ApplicationFailure::new(err),
262 )),
263 ),
264 }
265 }
266}
267
268impl From<ActivityExecutionError> for WorkflowTermination {
269 fn from(value: ActivityExecutionError) -> Self {
270 Self::Failed(value.into())
271 }
272}
273
274impl From<ChildWorkflowExecutionError> for WorkflowTermination {
275 fn from(value: ChildWorkflowExecutionError) -> Self {
276 Self::Failed(value.into())
277 }
278}
279
280impl From<WorkflowSignalError> for WorkflowTermination {
281 fn from(value: WorkflowSignalError) -> Self {
282 Self::Failed(value.into())
283 }
284}
285
286impl From<temporalio_common_wasm::error::ChildWorkflowStartError> for WorkflowTermination {
287 fn from(value: temporalio_common_wasm::error::ChildWorkflowStartError) -> Self {
288 Self::Failed(value.into())
289 }
290}