temporalio 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -23
  3. data/bridge/Cargo.lock +168 -59
  4. data/bridge/Cargo.toml +4 -2
  5. data/bridge/sdk-core/README.md +19 -6
  6. data/bridge/sdk-core/client/src/lib.rs +215 -39
  7. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  8. data/bridge/sdk-core/client/src/raw.rs +4 -4
  9. data/bridge/sdk-core/client/src/retry.rs +32 -20
  10. data/bridge/sdk-core/core/Cargo.toml +22 -9
  11. data/bridge/sdk-core/core/src/abstractions.rs +203 -14
  12. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
  13. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  14. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
  15. data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
  16. data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
  17. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
  18. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  19. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  20. data/bridge/sdk-core/core/src/lib.rs +16 -9
  21. data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
  22. data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
  23. data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
  24. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
  25. data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
  26. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  27. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  28. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
  29. data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
  30. data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
  31. data/bridge/sdk-core/core/src/worker/client.rs +18 -2
  32. data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
  33. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  34. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  35. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
  36. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
  37. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
  38. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
  39. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
  40. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
  41. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
  54. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
  55. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
  56. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
  57. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  58. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  60. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
  63. data/bridge/sdk-core/core-api/Cargo.toml +2 -1
  64. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  65. data/bridge/sdk-core/core-api/src/lib.rs +6 -2
  66. data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
  67. data/bridge/sdk-core/core-api/src/worker.rs +14 -1
  68. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  69. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  70. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  71. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  72. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  73. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  74. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  75. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  76. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  77. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  78. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  79. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  80. data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  81. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  82. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  83. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  84. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  85. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  86. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  87. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  88. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  89. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  90. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  91. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
  92. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
  93. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  94. data/bridge/sdk-core/sdk/Cargo.toml +3 -2
  95. data/bridge/sdk-core/sdk/src/lib.rs +87 -20
  96. data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
  97. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  98. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
  99. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
  100. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
  101. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
  102. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  103. data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
  104. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  105. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  106. data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
  107. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  108. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  109. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  110. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  111. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  115. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  116. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  117. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  118. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  120. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  121. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  122. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  123. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
  124. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
  125. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  126. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  127. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  129. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  130. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  131. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  132. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
  133. data/bridge/sdk-core/tests/main.rs +3 -13
  134. data/bridge/sdk-core/tests/runner.rs +75 -36
  135. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  136. data/bridge/src/connection.rs +41 -25
  137. data/bridge/src/lib.rs +269 -14
  138. data/bridge/src/runtime.rs +1 -1
  139. data/bridge/src/test_server.rs +153 -0
  140. data/bridge/src/worker.rs +89 -16
  141. data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
  142. data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
  143. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
  144. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
  145. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
  146. data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
  147. data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
  148. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
  149. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
  150. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  151. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  152. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  153. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  154. data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
  155. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
  156. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  157. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  158. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  159. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  160. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  161. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  162. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
  163. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
  164. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  165. data/lib/temporalio/activity/context.rb +13 -8
  166. data/lib/temporalio/activity/info.rb +1 -1
  167. data/lib/temporalio/bridge/connect_options.rb +15 -0
  168. data/lib/temporalio/bridge/retry_config.rb +24 -0
  169. data/lib/temporalio/bridge/tls_options.rb +19 -0
  170. data/lib/temporalio/client/implementation.rb +8 -8
  171. data/lib/temporalio/connection/retry_config.rb +44 -0
  172. data/lib/temporalio/connection/service.rb +20 -0
  173. data/lib/temporalio/connection/test_service.rb +92 -0
  174. data/lib/temporalio/connection/tls_options.rb +51 -0
  175. data/lib/temporalio/connection/workflow_service.rb +731 -0
  176. data/lib/temporalio/connection.rb +55 -720
  177. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  178. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  179. data/lib/temporalio/interceptor/chain.rb +5 -5
  180. data/lib/temporalio/interceptor/client.rb +8 -4
  181. data/lib/temporalio/interceptor.rb +22 -0
  182. data/lib/temporalio/retry_policy.rb +13 -3
  183. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  184. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  185. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  186. data/lib/temporalio/testing.rb +175 -0
  187. data/lib/temporalio/version.rb +1 -1
  188. data/lib/temporalio/worker/activity_runner.rb +26 -4
  189. data/lib/temporalio/worker/activity_worker.rb +44 -18
  190. data/lib/temporalio/worker/sync_worker.rb +47 -11
  191. data/lib/temporalio/worker.rb +27 -21
  192. data/lib/temporalio/workflow/async.rb +46 -0
  193. data/lib/temporalio/workflow/future.rb +138 -0
  194. data/lib/temporalio/workflow/info.rb +76 -0
  195. data/temporalio.gemspec +4 -3
  196. metadata +67 -17
  197. data/bridge/sdk-core/Cargo.lock +0 -2606
  198. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
  199. data/lib/bridge.so +0 -0
  200. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
  201. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
  202. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
@@ -2,6 +2,7 @@ use super::{
2
2
  workflow_machines::MachineResponse, Cancellable, EventInfo, NewMachineWithCommand,
3
3
  OnEventWrapper, WFMachinesAdapter, WFMachinesError,
4
4
  };
5
+ use crate::worker::workflow::machines::HistEventData;
5
6
  use rustfsm::{fsm, TransitionResult};
6
7
  use std::convert::TryFrom;
7
8
  use temporal_sdk_core_protos::{
@@ -85,16 +86,16 @@ impl From<FailWorkflowCommandCreated> for FailWorkflowCommandRecorded {
85
86
  }
86
87
  }
87
88
 
88
- impl TryFrom<HistoryEvent> for FailWorkflowMachineEvents {
89
+ impl TryFrom<HistEventData> for FailWorkflowMachineEvents {
89
90
  type Error = WFMachinesError;
90
91
 
91
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
92
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
93
+ let e = e.event;
92
94
  Ok(match e.event_type() {
93
95
  EventType::WorkflowExecutionFailed => Self::WorkflowExecutionFailed,
94
96
  _ => {
95
97
  return Err(WFMachinesError::Nondeterminism(format!(
96
- "Fail workflow machine does not handle this event: {}",
97
- e
98
+ "Fail workflow machine does not handle this event: {e}"
98
99
  )))
99
100
  }
100
101
  })
@@ -3,8 +3,12 @@ use super::{
3
3
  WFMachinesError,
4
4
  };
5
5
  use crate::{
6
+ internal_flags::CoreInternalFlags,
6
7
  protosext::{CompleteLocalActivityData, HistoryEventExt, ValidScheduleLA},
7
- worker::{workflow::OutgoingJob, LocalActivityExecutionResult},
8
+ worker::{
9
+ workflow::{machines::HistEventData, InternalFlagsRef, OutgoingJob},
10
+ LocalActivityExecutionResult,
11
+ },
8
12
  };
9
13
  use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
10
14
  use std::{
@@ -59,15 +63,17 @@ fsm! {
59
63
  --> MarkerCommandRecorded;
60
64
 
61
65
  // Replay path ================================================================================
62
- // LAs on the replay path should never have handle result explicitly called on them, but do need
63
- // to eventually see the marker
66
+ // LAs on the replay path always need to eventually see the marker
64
67
  WaitingMarkerEvent --(MarkerRecorded(CompleteLocalActivityData), shared on_marker_recorded)
65
68
  --> MarkerCommandRecorded;
66
69
  // If we are told to cancel while waiting for the marker, we still need to wait for the marker.
67
- WaitingMarkerEvent --(Cancel, on_cancel_requested) --> WaitingMarkerEventCancelled;
70
+ WaitingMarkerEvent --(Cancel, on_cancel_requested) --> WaitingMarkerEvent;
71
+ // Because there could be non-heartbeat WFTs (ex: signals being received) between scheduling
72
+ // the LA and the marker being recorded, peekahead might not always resolve the LA *before*
73
+ // scheduling it. This transition accounts for that.
74
+ WaitingMarkerEvent --(HandleKnownResult(ResolveDat), on_handle_result) --> WaitingMarkerEvent;
68
75
  WaitingMarkerEvent --(NoWaitCancel(ActivityCancellationType),
69
- on_no_wait_cancel) --> WaitingMarkerEventCancelled;
70
- WaitingMarkerEventCancelled --(HandleResult(ResolveDat), on_handle_result) --> WaitingMarkerEvent;
76
+ on_no_wait_cancel) --> WaitingMarkerEvent;
71
77
 
72
78
  // It is entirely possible to have started the LA while replaying, only to find that we have
73
79
  // reached a new WFT and there still was no marker. In such cases we need to execute the LA.
@@ -139,6 +145,7 @@ pub(super) fn new_local_activity(
139
145
  replaying_when_invoked: bool,
140
146
  maybe_pre_resolved: Option<ResolveDat>,
141
147
  wf_time: Option<SystemTime>,
148
+ internal_flags: InternalFlagsRef,
142
149
  ) -> Result<(LocalActivityMachine, Vec<MachineResponse>), WFMachinesError> {
143
150
  let initial_state = if replaying_when_invoked {
144
151
  if let Some(dat) = maybe_pre_resolved {
@@ -166,6 +173,7 @@ pub(super) fn new_local_activity(
166
173
  attrs,
167
174
  replaying_when_invoked,
168
175
  wf_time_when_started: wf_time,
176
+ internal_flags,
169
177
  },
170
178
  };
171
179
 
@@ -202,6 +210,12 @@ impl LocalActivityMachine {
202
210
  }
203
211
  }
204
212
 
213
+ /// Returns true if the machine will willingly accept data from a marker in its current state.
214
+ /// IE: Calling [Self::try_resolve_with_dat] makes sense.
215
+ pub(super) fn will_accept_resolve_marker(&self) -> bool {
216
+ matches!(self.state, LocalActivityMachineState::WaitingMarkerEvent(_))
217
+ }
218
+
205
219
  /// Must be called if the workflow encounters a non-replay workflow task
206
220
  pub(super) fn encountered_non_replay_wft(
207
221
  &mut self,
@@ -240,28 +254,45 @@ impl LocalActivityMachine {
240
254
  backoff: Option<prost_types::Duration>,
241
255
  original_schedule_time: Option<SystemTime>,
242
256
  ) -> Result<Vec<MachineResponse>, WFMachinesError> {
243
- self.try_resolve_with_dat(ResolveDat {
244
- result,
245
- complete_time: self.shared_state.wf_time_when_started.map(|t| t + runtime),
246
- attempt,
247
- backoff,
248
- original_schedule_time,
249
- })
257
+ self._try_resolve(
258
+ ResolveDat {
259
+ result,
260
+ complete_time: self.shared_state.wf_time_when_started.map(|t| t + runtime),
261
+ attempt,
262
+ backoff,
263
+ original_schedule_time,
264
+ },
265
+ false,
266
+ )
250
267
  }
268
+
251
269
  /// Attempt to resolve the local activity with already known data, ex pre-resolved data
252
270
  pub(super) fn try_resolve_with_dat(
253
271
  &mut self,
254
272
  dat: ResolveDat,
255
273
  ) -> Result<Vec<MachineResponse>, WFMachinesError> {
256
- let res = OnEventWrapper::on_event_mut(self, LocalActivityMachineEvents::HandleResult(dat))
257
- .map_err(|e| match e {
258
- MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
259
- "Invalid transition resolving local activity (seq {}) in {}",
260
- self.shared_state.attrs.seq,
261
- self.state(),
262
- )),
263
- MachineError::Underlying(e) => e,
264
- })?;
274
+ self._try_resolve(dat, true)
275
+ }
276
+
277
+ fn _try_resolve(
278
+ &mut self,
279
+ dat: ResolveDat,
280
+ from_marker: bool,
281
+ ) -> Result<Vec<MachineResponse>, WFMachinesError> {
282
+ let evt = if from_marker {
283
+ LocalActivityMachineEvents::HandleKnownResult(dat)
284
+ } else {
285
+ LocalActivityMachineEvents::HandleResult(dat)
286
+ };
287
+ let res = OnEventWrapper::on_event_mut(self, evt).map_err(|e| match e {
288
+ MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
289
+ "Invalid transition resolving local activity (seq {}, from marker: {}) in {}",
290
+ self.shared_state.attrs.seq,
291
+ from_marker,
292
+ self.state(),
293
+ )),
294
+ MachineError::Underlying(e) => e,
295
+ })?;
265
296
 
266
297
  Ok(res
267
298
  .into_iter()
@@ -278,6 +309,7 @@ pub(super) struct SharedState {
278
309
  attrs: ValidScheduleLA,
279
310
  replaying_when_invoked: bool,
280
311
  wf_time_when_started: Option<SystemTime>,
312
+ internal_flags: InternalFlagsRef,
281
313
  }
282
314
 
283
315
  impl SharedState {
@@ -510,6 +542,17 @@ impl WaitingMarkerEvent {
510
542
  })
511
543
  )
512
544
  }
545
+ fn on_handle_result(
546
+ self,
547
+ dat: ResolveDat,
548
+ ) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
549
+ TransitionResult::ok(
550
+ [LocalActivityCommand::Resolved(dat)],
551
+ WaitingMarkerEvent {
552
+ already_resolved: true,
553
+ },
554
+ )
555
+ }
513
556
  pub(super) fn on_started_non_replay_wft(
514
557
  self,
515
558
  mut dat: SharedState,
@@ -525,41 +568,22 @@ impl WaitingMarkerEvent {
525
568
  )
526
569
  }
527
570
 
528
- fn on_cancel_requested(self) -> LocalActivityMachineTransition<WaitingMarkerEventCancelled> {
571
+ fn on_cancel_requested(self) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
529
572
  // We still "request a cancel" even though we know the local activity should not be running
530
573
  // because the data might be in the pre-resolved list.
531
- TransitionResult::ok(
532
- [LocalActivityCommand::RequestCancel],
533
- WaitingMarkerEventCancelled {},
534
- )
574
+ TransitionResult::ok([LocalActivityCommand::RequestCancel], self)
535
575
  }
536
576
 
537
577
  fn on_no_wait_cancel(
538
578
  self,
539
579
  _: ActivityCancellationType,
540
- ) -> LocalActivityMachineTransition<WaitingMarkerEventCancelled> {
580
+ ) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
541
581
  // Markers are always recorded when cancelling, so this is the same as a normal cancel on
542
582
  // the replay path
543
583
  self.on_cancel_requested()
544
584
  }
545
585
  }
546
586
 
547
- #[derive(Default, Clone)]
548
- pub(super) struct WaitingMarkerEventCancelled {}
549
- impl WaitingMarkerEventCancelled {
550
- fn on_handle_result(
551
- self,
552
- dat: ResolveDat,
553
- ) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
554
- TransitionResult::ok(
555
- [LocalActivityCommand::Resolved(dat)],
556
- WaitingMarkerEvent {
557
- already_resolved: true,
558
- },
559
- )
560
- }
561
- }
562
-
563
587
  #[derive(Default, Clone)]
564
588
  pub(super) struct WaitingMarkerEventPreResolved {}
565
589
  impl WaitingMarkerEventPreResolved {
@@ -732,14 +756,14 @@ impl TryFrom<CommandType> for LocalActivityMachineEvents {
732
756
  }
733
757
  }
734
758
 
735
- impl TryFrom<HistoryEvent> for LocalActivityMachineEvents {
759
+ impl TryFrom<HistEventData> for LocalActivityMachineEvents {
736
760
  type Error = WFMachinesError;
737
761
 
738
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
762
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
763
+ let e = e.event;
739
764
  if e.event_type() != EventType::MarkerRecorded {
740
765
  return Err(WFMachinesError::Nondeterminism(format!(
741
- "Local activity machine cannot handle this event: {}",
742
- e
766
+ "Local activity machine cannot handle this event: {e}"
743
767
  )));
744
768
  }
745
769
 
@@ -763,6 +787,28 @@ fn verify_marker_data_matches(
763
787
  dat.marker_dat.seq, shared.attrs.seq
764
788
  )));
765
789
  }
790
+ // Here we use whether or not we were replaying when we _first invoked_ the LA, because we
791
+ // are always replaying when we see the marker recorded event, and that would make this check
792
+ // a bit pointless.
793
+ if shared.internal_flags.borrow_mut().try_use(
794
+ CoreInternalFlags::IdAndTypeDeterminismChecks,
795
+ !shared.replaying_when_invoked,
796
+ ) {
797
+ if dat.marker_dat.activity_id != shared.attrs.activity_id {
798
+ return Err(WFMachinesError::Nondeterminism(format!(
799
+ "Activity id of recorded marker '{}' does not \
800
+ match activity id of local activity command '{}'",
801
+ dat.marker_dat.activity_id, shared.attrs.activity_id
802
+ )));
803
+ }
804
+ if dat.marker_dat.activity_type != shared.attrs.activity_type {
805
+ return Err(WFMachinesError::Nondeterminism(format!(
806
+ "Activity type of recorded marker '{}' does not \
807
+ match activity type of local activity command '{}'",
808
+ dat.marker_dat.activity_type, shared.attrs.activity_type
809
+ )));
810
+ }
811
+ }
766
812
 
767
813
  Ok(())
768
814
  }
@@ -805,10 +851,15 @@ mod tests {
805
851
  temporal::api::{
806
852
  command::v1::command, enums::v1::WorkflowTaskFailedCause, failure::v1::Failure,
807
853
  },
854
+ DEFAULT_ACTIVITY_TYPE,
808
855
  };
809
856
 
810
857
  async fn la_wf(ctx: WfContext) -> WorkflowResult<()> {
811
- ctx.local_activity(LocalActivityOptions::default()).await;
858
+ ctx.local_activity(LocalActivityOptions {
859
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
860
+ ..Default::default()
861
+ })
862
+ .await;
812
863
  Ok(().into())
813
864
  }
814
865
 
@@ -921,8 +972,16 @@ mod tests {
921
972
  }
922
973
 
923
974
  async fn two_la_wf(ctx: WfContext) -> WorkflowResult<()> {
924
- ctx.local_activity(LocalActivityOptions::default()).await;
925
- ctx.local_activity(LocalActivityOptions::default()).await;
975
+ ctx.local_activity(LocalActivityOptions {
976
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
977
+ ..Default::default()
978
+ })
979
+ .await;
980
+ ctx.local_activity(LocalActivityOptions {
981
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
982
+ ..Default::default()
983
+ })
984
+ .await;
926
985
  Ok(().into())
927
986
  }
928
987
 
@@ -1015,8 +1074,14 @@ mod tests {
1015
1074
 
1016
1075
  async fn two_la_wf_parallel(ctx: WfContext) -> WorkflowResult<()> {
1017
1076
  tokio::join!(
1018
- ctx.local_activity(LocalActivityOptions::default()),
1019
- ctx.local_activity(LocalActivityOptions::default())
1077
+ ctx.local_activity(LocalActivityOptions {
1078
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1079
+ ..Default::default()
1080
+ }),
1081
+ ctx.local_activity(LocalActivityOptions {
1082
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1083
+ ..Default::default()
1084
+ })
1020
1085
  );
1021
1086
  Ok(().into())
1022
1087
  }
@@ -1099,9 +1164,17 @@ mod tests {
1099
1164
  }
1100
1165
 
1101
1166
  async fn la_timer_la(ctx: WfContext) -> WorkflowResult<()> {
1102
- ctx.local_activity(LocalActivityOptions::default()).await;
1167
+ ctx.local_activity(LocalActivityOptions {
1168
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1169
+ ..Default::default()
1170
+ })
1171
+ .await;
1103
1172
  ctx.timer(Duration::from_secs(5)).await;
1104
- ctx.local_activity(LocalActivityOptions::default()).await;
1173
+ ctx.local_activity(LocalActivityOptions {
1174
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1175
+ ..Default::default()
1176
+ })
1177
+ .await;
1105
1178
  Ok(().into())
1106
1179
  }
1107
1180
 
@@ -1342,6 +1415,7 @@ mod tests {
1342
1415
  let func = WorkflowFunction::new(move |ctx| async move {
1343
1416
  let la = ctx.local_activity(LocalActivityOptions {
1344
1417
  cancel_type,
1418
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1345
1419
  ..Default::default()
1346
1420
  });
1347
1421
  ctx.timer(Duration::from_secs(1)).await;
@@ -1357,14 +1431,14 @@ mod tests {
1357
1431
  let mut t = TestHistoryBuilder::default();
1358
1432
  t.add_by_type(EventType::WorkflowExecutionStarted);
1359
1433
  t.add_full_wf_task();
1360
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1434
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1361
1435
  t.add_timer_fired(timer_started_event_id, "1".to_string());
1362
1436
  t.add_full_wf_task();
1363
1437
  if cancel_type != ActivityCancellationType::WaitCancellationCompleted {
1364
1438
  // With non-wait cancels, the cancel is immediate
1365
1439
  t.add_local_activity_cancel_marker(1, "1");
1366
1440
  }
1367
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1441
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1368
1442
  if cancel_type == ActivityCancellationType::WaitCancellationCompleted {
1369
1443
  // With wait cancels, the cancel marker is not recorded until activity reports.
1370
1444
  t.add_local_activity_cancel_marker(1, "1");
@@ -1408,8 +1482,9 @@ mod tests {
1408
1482
  assert_eq!(commands[1].command_type, CommandType::StartTimer as i32);
1409
1483
  }
1410
1484
 
1411
- if replay {
1412
- wfm.get_next_activation().await.unwrap()
1485
+ let commands = if replay {
1486
+ wfm.get_next_activation().await.unwrap();
1487
+ wfm.get_server_commands().commands
1413
1488
  } else {
1414
1489
  // On non replay, there's an additional activation, because completing with the cancel
1415
1490
  // wants to wake up the workflow to see if resolving the LA as cancelled did anything.
@@ -1434,11 +1509,11 @@ mod tests {
1434
1509
 
1435
1510
  wfm.new_history(t.get_history_info(3).unwrap().into())
1436
1511
  .await
1437
- .unwrap()
1512
+ .unwrap();
1513
+ wfm.get_next_activation().await.unwrap();
1514
+ wfm.get_server_commands().commands
1438
1515
  };
1439
1516
 
1440
- wfm.get_next_activation().await.unwrap();
1441
- let commands = wfm.get_server_commands().commands;
1442
1517
  assert_eq!(commands.len(), 1);
1443
1518
  assert_eq!(
1444
1519
  commands[0].command_type,
@@ -18,9 +18,9 @@ mod workflow_task_state_machine;
18
18
  #[cfg(test)]
19
19
  mod transition_coverage;
20
20
 
21
- pub(crate) use workflow_machines::{WFMachinesError, WorkflowMachines};
21
+ pub(crate) use workflow_machines::WorkflowMachines;
22
22
 
23
- use crate::telemetry::VecDisplayer;
23
+ use crate::{telemetry::VecDisplayer, worker::workflow::WFMachinesError};
24
24
  use activity_state_machine::ActivityMachine;
25
25
  use cancel_external_state_machine::CancelExternalMachine;
26
26
  use cancel_workflow_state_machine::CancelWorkflowMachine;
@@ -73,7 +73,7 @@ enum Machines {
73
73
  ///
74
74
  /// Formerly known as `EntityStateMachine` in Java.
75
75
  #[enum_dispatch::enum_dispatch(Machines)]
76
- trait TemporalStateMachine: Send {
76
+ trait TemporalStateMachine {
77
77
  fn handle_command(
78
78
  &mut self,
79
79
  command_type: CommandType,
@@ -88,8 +88,7 @@ trait TemporalStateMachine: Send {
88
88
  /// to update the overall state of the workflow. EX: To issue outgoing WF activations.
89
89
  fn handle_event(
90
90
  &mut self,
91
- event: HistoryEvent,
92
- has_next_event: bool,
91
+ event: HistEventData,
93
92
  ) -> Result<Vec<MachineResponse>, WFMachinesError>;
94
93
 
95
94
  /// Attempt to cancel the command associated with this state machine, if it is cancellable
@@ -108,9 +107,9 @@ trait TemporalStateMachine: Send {
108
107
 
109
108
  impl<SM> TemporalStateMachine for SM
110
109
  where
111
- SM: StateMachine + WFMachinesAdapter + Cancellable + OnEventWrapper + Clone + Send + 'static,
112
- <SM as StateMachine>::Event: TryFrom<HistoryEvent> + TryFrom<CommandType> + Display,
113
- WFMachinesError: From<<<SM as StateMachine>::Event as TryFrom<HistoryEvent>>::Error>,
110
+ SM: StateMachine + WFMachinesAdapter + Cancellable + OnEventWrapper + Clone + 'static,
111
+ <SM as StateMachine>::Event: TryFrom<HistEventData> + TryFrom<CommandType> + Display,
112
+ WFMachinesError: From<<<SM as StateMachine>::Event as TryFrom<HistEventData>>::Error>,
114
113
  <SM as StateMachine>::Command: Debug + Display,
115
114
  <SM as StateMachine>::State: Display,
116
115
  <SM as StateMachine>::Error: Into<WFMachinesError> + 'static + Send + Sync,
@@ -152,21 +151,19 @@ where
152
151
 
153
152
  fn handle_event(
154
153
  &mut self,
155
- event: HistoryEvent,
156
- has_next_event: bool,
154
+ event_dat: HistEventData,
157
155
  ) -> Result<Vec<MachineResponse>, WFMachinesError> {
158
156
  trace!(
159
- event = %event,
157
+ event = %event_dat.event,
160
158
  machine_name = %self.name(),
161
159
  state = %self.state(),
162
160
  "handling event"
163
161
  );
164
162
  let event_info = EventInfo {
165
- event_id: event.event_id,
166
- event_type: event.event_type(),
167
- has_next_event,
163
+ event_id: event_dat.event.event_id,
164
+ event_type: event_dat.event.event_type(),
168
165
  };
169
- let converted_event: <Self as StateMachine>::Event = event.try_into()?;
166
+ let converted_event: <Self as StateMachine>::Event = event_dat.try_into()?;
170
167
 
171
168
  match OnEventWrapper::on_event_mut(self, converted_event) {
172
169
  Ok(c) => process_machine_commands(self, c, Some(event_info)),
@@ -217,7 +214,7 @@ where
217
214
  <SM as StateMachine>::State: Display,
218
215
  {
219
216
  if !commands.is_empty() {
220
- debug!(commands=%commands.display(), state=%machine.state(),
217
+ trace!(commands=%commands.display(), state=%machine.state(),
221
218
  machine_name=%TemporalStateMachine::name(machine), "Machine produced commands");
222
219
  }
223
220
  let mut machine_responses = vec![];
@@ -245,11 +242,22 @@ trait WFMachinesAdapter: StateMachine {
245
242
  fn matches_event(&self, event: &HistoryEvent) -> bool;
246
243
  }
247
244
 
245
+ /// Wraps a history event with extra relevant data that a machine might care about while the event
246
+ /// is being applied to it.
247
+ #[derive(Debug, derive_more::Display)]
248
+ #[display(fmt = "{event}")]
249
+ struct HistEventData {
250
+ event: HistoryEvent,
251
+ /// Is the current workflow task under replay or not during application of this event?
252
+ replaying: bool,
253
+ /// Is the current workflow task the last task in history?
254
+ current_task_is_last_in_history: bool,
255
+ }
256
+
248
257
  #[derive(Debug, Copy, Clone)]
249
258
  struct EventInfo {
250
259
  event_id: i64,
251
260
  event_type: EventType,
252
- has_next_event: bool,
253
261
  }
254
262
 
255
263
  trait Cancellable: StateMachine {
@@ -1,8 +1,8 @@
1
- use super::{
2
- workflow_machines::{MachineResponse, WFMachinesError},
3
- NewMachineWithCommand,
1
+ use super::{workflow_machines::MachineResponse, NewMachineWithCommand};
2
+ use crate::worker::workflow::{
3
+ machines::{Cancellable, EventInfo, HistEventData, WFMachinesAdapter},
4
+ WFMachinesError,
4
5
  };
5
- use crate::worker::workflow::machines::{Cancellable, EventInfo, WFMachinesAdapter};
6
6
  use rustfsm::{fsm, TransitionResult};
7
7
  use temporal_sdk_core_protos::{
8
8
  coresdk::workflow_commands::ModifyWorkflowProperties,
@@ -74,10 +74,11 @@ impl WFMachinesAdapter for ModifyWorkflowPropertiesMachine {
74
74
 
75
75
  impl Cancellable for ModifyWorkflowPropertiesMachine {}
76
76
 
77
- impl TryFrom<HistoryEvent> for ModifyWorkflowPropertiesMachineEvents {
77
+ impl TryFrom<HistEventData> for ModifyWorkflowPropertiesMachineEvents {
78
78
  type Error = WFMachinesError;
79
79
 
80
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
80
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
81
+ let e = e.event;
81
82
  match e.event_type() {
82
83
  EventType::WorkflowPropertiesModified => {
83
84
  Ok(ModifyWorkflowPropertiesMachineEvents::CommandRecorded)