@temporalio/core-bridge 1.5.2 → 1.7.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 (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -4
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -3,8 +3,15 @@ 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::{
10
+ machines::{activity_state_machine::activity_fail_info, HistEventData},
11
+ InternalFlagsRef, OutgoingJob,
12
+ },
13
+ LocalActivityExecutionResult,
14
+ },
8
15
  };
9
16
  use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
10
17
  use std::{
@@ -24,8 +31,8 @@ use temporal_sdk_core_protos::{
24
31
  },
25
32
  temporal::api::{
26
33
  command::v1::{Command, RecordMarkerCommandAttributes},
27
- enums::v1::{CommandType, EventType},
28
- failure::v1::failure::FailureInfo,
34
+ enums::v1::{CommandType, EventType, RetryState},
35
+ failure::v1::{failure::FailureInfo, Failure},
29
36
  history::v1::HistoryEvent,
30
37
  },
31
38
  utilities::TryIntoOrNone,
@@ -59,15 +66,17 @@ fsm! {
59
66
  --> MarkerCommandRecorded;
60
67
 
61
68
  // 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
69
+ // LAs on the replay path always need to eventually see the marker
64
70
  WaitingMarkerEvent --(MarkerRecorded(CompleteLocalActivityData), shared on_marker_recorded)
65
71
  --> MarkerCommandRecorded;
66
72
  // 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;
73
+ WaitingMarkerEvent --(Cancel, on_cancel_requested) --> WaitingMarkerEvent;
74
+ // Because there could be non-heartbeat WFTs (ex: signals being received) between scheduling
75
+ // the LA and the marker being recorded, peekahead might not always resolve the LA *before*
76
+ // scheduling it. This transition accounts for that.
77
+ WaitingMarkerEvent --(HandleKnownResult(ResolveDat), on_handle_result) --> WaitingMarkerEvent;
68
78
  WaitingMarkerEvent --(NoWaitCancel(ActivityCancellationType),
69
- on_no_wait_cancel) --> WaitingMarkerEventCancelled;
70
- WaitingMarkerEventCancelled --(HandleResult(ResolveDat), on_handle_result) --> WaitingMarkerEvent;
79
+ on_no_wait_cancel) --> WaitingMarkerEvent;
71
80
 
72
81
  // It is entirely possible to have started the LA while replaying, only to find that we have
73
82
  // reached a new WFT and there still was no marker. In such cases we need to execute the LA.
@@ -111,7 +120,12 @@ impl From<CompleteLocalActivityData> for ResolveDat {
111
120
  result: match d.result {
112
121
  Ok(res) => LocalActivityExecutionResult::Completed(Success { result: Some(res) }),
113
122
  Err(fail) => {
114
- if matches!(fail.failure_info, Some(FailureInfo::CanceledFailureInfo(_))) {
123
+ if matches!(fail.failure_info, Some(FailureInfo::CanceledFailureInfo(_)))
124
+ || matches!(
125
+ fail.cause.as_deref().and_then(|f| f.failure_info.as_ref()),
126
+ Some(FailureInfo::CanceledFailureInfo(_))
127
+ )
128
+ {
115
129
  LocalActivityExecutionResult::Cancelled(Cancellation {
116
130
  failure: Some(fail),
117
131
  })
@@ -135,10 +149,11 @@ impl From<CompleteLocalActivityData> for ResolveDat {
135
149
  /// must resolve before we send a record marker command. A [MachineResponse] may be produced,
136
150
  /// to queue the LA for execution if it needs to be.
137
151
  pub(super) fn new_local_activity(
138
- attrs: ValidScheduleLA,
152
+ mut attrs: ValidScheduleLA,
139
153
  replaying_when_invoked: bool,
140
154
  maybe_pre_resolved: Option<ResolveDat>,
141
155
  wf_time: Option<SystemTime>,
156
+ internal_flags: InternalFlagsRef,
142
157
  ) -> Result<(LocalActivityMachine, Vec<MachineResponse>), WFMachinesError> {
143
158
  let initial_state = if replaying_when_invoked {
144
159
  if let Some(dat) = maybe_pre_resolved {
@@ -155,14 +170,20 @@ pub(super) fn new_local_activity(
155
170
  Executing {}.into()
156
171
  };
157
172
 
158
- let mut machine = LocalActivityMachine {
159
- state: initial_state,
160
- shared_state: SharedState {
173
+ // If the scheduled LA doesn't already have an "original" schedule time, assign one.
174
+ attrs
175
+ .original_schedule_time
176
+ .get_or_insert(SystemTime::now());
177
+
178
+ let mut machine = LocalActivityMachine::from_parts(
179
+ initial_state,
180
+ SharedState {
161
181
  attrs,
162
182
  replaying_when_invoked,
163
183
  wf_time_when_started: wf_time,
184
+ internal_flags,
164
185
  },
165
- };
186
+ );
166
187
 
167
188
  let mut res = OnEventWrapper::on_event_mut(&mut machine, LocalActivityMachineEvents::Schedule)
168
189
  .expect("Scheduling local activities doesn't fail");
@@ -186,17 +207,26 @@ impl LocalActivityMachine {
186
207
  ///
187
208
  /// Attempting the check in any other state likely means a bug in the SDK.
188
209
  pub(super) fn marker_should_get_special_handling(&self) -> Result<bool, WFMachinesError> {
189
- match &self.state {
210
+ match self.state() {
190
211
  LocalActivityMachineState::ResultNotified(_) => Ok(false),
191
212
  LocalActivityMachineState::WaitingMarkerEvent(_) => Ok(true),
192
213
  LocalActivityMachineState::WaitingMarkerEventPreResolved(_) => Ok(true),
193
214
  _ => Err(WFMachinesError::Fatal(format!(
194
215
  "Attempted to check for LA marker handling in invalid state {}",
195
- self.state
216
+ self.state()
196
217
  ))),
197
218
  }
198
219
  }
199
220
 
221
+ /// Returns true if the machine will willingly accept data from a marker in its current state.
222
+ /// IE: Calling [Self::try_resolve_with_dat] makes sense.
223
+ pub(super) fn will_accept_resolve_marker(&self) -> bool {
224
+ matches!(
225
+ self.state(),
226
+ LocalActivityMachineState::WaitingMarkerEvent(_)
227
+ )
228
+ }
229
+
200
230
  /// Must be called if the workflow encounters a non-replay workflow task
201
231
  pub(super) fn encountered_non_replay_wft(
202
232
  &mut self,
@@ -235,28 +265,45 @@ impl LocalActivityMachine {
235
265
  backoff: Option<prost_types::Duration>,
236
266
  original_schedule_time: Option<SystemTime>,
237
267
  ) -> Result<Vec<MachineResponse>, WFMachinesError> {
238
- self.try_resolve_with_dat(ResolveDat {
239
- result,
240
- complete_time: self.shared_state.wf_time_when_started.map(|t| t + runtime),
241
- attempt,
242
- backoff,
243
- original_schedule_time,
244
- })
268
+ self._try_resolve(
269
+ ResolveDat {
270
+ result,
271
+ complete_time: self.shared_state.wf_time_when_started.map(|t| t + runtime),
272
+ attempt,
273
+ backoff,
274
+ original_schedule_time,
275
+ },
276
+ false,
277
+ )
245
278
  }
279
+
246
280
  /// Attempt to resolve the local activity with already known data, ex pre-resolved data
247
281
  pub(super) fn try_resolve_with_dat(
248
282
  &mut self,
249
283
  dat: ResolveDat,
250
284
  ) -> Result<Vec<MachineResponse>, WFMachinesError> {
251
- let res = OnEventWrapper::on_event_mut(self, LocalActivityMachineEvents::HandleResult(dat))
252
- .map_err(|e| match e {
253
- MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
254
- "Invalid transition resolving local activity (seq {}) in {}",
255
- self.shared_state.attrs.seq,
256
- self.state(),
257
- )),
258
- MachineError::Underlying(e) => e,
259
- })?;
285
+ self._try_resolve(dat, true)
286
+ }
287
+
288
+ fn _try_resolve(
289
+ &mut self,
290
+ dat: ResolveDat,
291
+ from_marker: bool,
292
+ ) -> Result<Vec<MachineResponse>, WFMachinesError> {
293
+ let evt = if from_marker {
294
+ LocalActivityMachineEvents::HandleKnownResult(dat)
295
+ } else {
296
+ LocalActivityMachineEvents::HandleResult(dat)
297
+ };
298
+ let res = OnEventWrapper::on_event_mut(self, evt).map_err(|e| match e {
299
+ MachineError::InvalidTransition => WFMachinesError::Fatal(format!(
300
+ "Invalid transition resolving local activity (seq {}, from marker: {}) in {}",
301
+ self.shared_state.attrs.seq,
302
+ from_marker,
303
+ self.state(),
304
+ )),
305
+ MachineError::Underlying(e) => e,
306
+ })?;
260
307
 
261
308
  Ok(res
262
309
  .into_iter()
@@ -273,6 +320,7 @@ pub(super) struct SharedState {
273
320
  attrs: ValidScheduleLA,
274
321
  replaying_when_invoked: bool,
275
322
  wf_time_when_started: Option<SystemTime>,
323
+ internal_flags: InternalFlagsRef,
276
324
  }
277
325
 
278
326
  impl SharedState {
@@ -314,9 +362,11 @@ pub(super) struct Executing {}
314
362
  impl Executing {
315
363
  pub(super) fn on_schedule(
316
364
  self,
317
- dat: SharedState,
365
+ dat: &mut SharedState,
318
366
  ) -> LocalActivityMachineTransition<RequestSent> {
319
- TransitionResult::commands([LocalActivityCommand::RequestActivityExecution(dat.attrs)])
367
+ TransitionResult::commands([LocalActivityCommand::RequestActivityExecution(
368
+ dat.attrs.clone(),
369
+ )])
320
370
  }
321
371
  }
322
372
 
@@ -426,7 +476,7 @@ impl RequestSent {
426
476
 
427
477
  fn on_no_wait_cancel(
428
478
  self,
429
- shared: SharedState,
479
+ shared: &mut SharedState,
430
480
  cancel_type: ActivityCancellationType,
431
481
  ) -> LocalActivityMachineTransition<MarkerCommandCreated> {
432
482
  let mut cmds = vec![];
@@ -465,7 +515,7 @@ pub(super) struct ResultNotified {
465
515
  impl ResultNotified {
466
516
  pub(super) fn on_marker_recorded(
467
517
  self,
468
- shared: SharedState,
518
+ shared: &mut SharedState,
469
519
  dat: CompleteLocalActivityData,
470
520
  ) -> LocalActivityMachineTransition<MarkerCommandRecorded> {
471
521
  if self.result_type == ResultType::Completed && dat.result.is_err() {
@@ -480,7 +530,7 @@ impl ResultNotified {
480
530
  shared.attrs.seq
481
531
  )));
482
532
  }
483
- verify_marker_dat!(&shared, &dat, TransitionResult::default())
533
+ verify_marker_dat!(shared, &dat, TransitionResult::default())
484
534
  }
485
535
  }
486
536
 
@@ -492,11 +542,11 @@ pub(super) struct WaitingMarkerEvent {
492
542
  impl WaitingMarkerEvent {
493
543
  pub(super) fn on_marker_recorded(
494
544
  self,
495
- shared: SharedState,
545
+ shared: &mut SharedState,
496
546
  dat: CompleteLocalActivityData,
497
547
  ) -> LocalActivityMachineTransition<MarkerCommandRecorded> {
498
548
  verify_marker_dat!(
499
- &shared,
549
+ shared,
500
550
  &dat,
501
551
  TransitionResult::commands(if self.already_resolved {
502
552
  vec![]
@@ -505,65 +555,53 @@ impl WaitingMarkerEvent {
505
555
  })
506
556
  )
507
557
  }
558
+ fn on_handle_result(
559
+ self,
560
+ dat: ResolveDat,
561
+ ) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
562
+ TransitionResult::ok(
563
+ [LocalActivityCommand::Resolved(dat)],
564
+ WaitingMarkerEvent {
565
+ already_resolved: true,
566
+ },
567
+ )
568
+ }
508
569
  pub(super) fn on_started_non_replay_wft(
509
570
  self,
510
- mut dat: SharedState,
571
+ dat: &mut SharedState,
511
572
  ) -> LocalActivityMachineTransition<RequestSent> {
512
573
  // We aren't really "replaying" anymore for our purposes, and want to record the marker.
513
574
  dat.replaying_when_invoked = false;
514
- TransitionResult::ok_shared(
515
- [LocalActivityCommand::RequestActivityExecution(
516
- dat.attrs.clone(),
517
- )],
518
- RequestSent::default(),
519
- dat,
520
- )
575
+ TransitionResult::commands([LocalActivityCommand::RequestActivityExecution(
576
+ dat.attrs.clone(),
577
+ )])
521
578
  }
522
579
 
523
- fn on_cancel_requested(self) -> LocalActivityMachineTransition<WaitingMarkerEventCancelled> {
580
+ fn on_cancel_requested(self) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
524
581
  // We still "request a cancel" even though we know the local activity should not be running
525
582
  // because the data might be in the pre-resolved list.
526
- TransitionResult::ok(
527
- [LocalActivityCommand::RequestCancel],
528
- WaitingMarkerEventCancelled {},
529
- )
583
+ TransitionResult::ok([LocalActivityCommand::RequestCancel], self)
530
584
  }
531
585
 
532
586
  fn on_no_wait_cancel(
533
587
  self,
534
588
  _: ActivityCancellationType,
535
- ) -> LocalActivityMachineTransition<WaitingMarkerEventCancelled> {
589
+ ) -> LocalActivityMachineTransition<WaitingMarkerEvent> {
536
590
  // Markers are always recorded when cancelling, so this is the same as a normal cancel on
537
591
  // the replay path
538
592
  self.on_cancel_requested()
539
593
  }
540
594
  }
541
595
 
542
- #[derive(Default, Clone)]
543
- pub(super) struct WaitingMarkerEventCancelled {}
544
- impl WaitingMarkerEventCancelled {
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
- }
556
- }
557
-
558
596
  #[derive(Default, Clone)]
559
597
  pub(super) struct WaitingMarkerEventPreResolved {}
560
598
  impl WaitingMarkerEventPreResolved {
561
599
  pub(super) fn on_marker_recorded(
562
600
  self,
563
- shared: SharedState,
601
+ shared: &mut SharedState,
564
602
  dat: CompleteLocalActivityData,
565
603
  ) -> LocalActivityMachineTransition<MarkerCommandRecorded> {
566
- verify_marker_dat!(&shared, &dat, TransitionResult::default())
604
+ verify_marker_dat!(shared, &dat, TransitionResult::default())
567
605
  }
568
606
  }
569
607
 
@@ -645,8 +683,61 @@ impl WFMachinesAdapter for LocalActivityMachine {
645
683
  ),
646
684
  }
647
685
  } else {
648
- result.into()
686
+ // Cancels and timeouts are to be wrapped with an activity failure
687
+ macro_rules! wrap_fail {
688
+ ($me:ident, $fail:ident, $msg:expr, $info:pat) => {
689
+ let mut fail = $fail.failure.take();
690
+ let fail_info = fail.as_ref().and_then(|f| f.failure_info.as_ref());
691
+ if matches!(fail_info, Some($info)) {
692
+ fail = Some(Failure {
693
+ message: $msg,
694
+ cause: fail.map(Box::new),
695
+ failure_info: Some(activity_fail_info(
696
+ $me.shared_state.attrs.activity_type.clone(),
697
+ $me.shared_state.attrs.activity_id.clone(),
698
+ None,
699
+ RetryState::CancelRequested,
700
+ 0,
701
+ 0,
702
+ )),
703
+ ..Default::default()
704
+ });
705
+ }
706
+ $fail.failure = fail;
707
+ };
708
+ }
709
+ match result {
710
+ LocalActivityExecutionResult::Completed(c) => ActivityResolution {
711
+ status: Some(c.into()),
712
+ },
713
+ LocalActivityExecutionResult::Failed(f) => ActivityResolution {
714
+ status: Some(f.into()),
715
+ },
716
+ LocalActivityExecutionResult::TimedOut(mut failure) => {
717
+ wrap_fail!(
718
+ self,
719
+ failure,
720
+ "Local Activity timed out".to_string(),
721
+ FailureInfo::TimeoutFailureInfo(_)
722
+ );
723
+ ActivityResolution {
724
+ status: Some(failure.into()),
725
+ }
726
+ }
727
+ LocalActivityExecutionResult::Cancelled(mut cancel) => {
728
+ wrap_fail!(
729
+ self,
730
+ cancel,
731
+ "Local Activity cancelled".to_string(),
732
+ FailureInfo::CanceledFailureInfo(_)
733
+ );
734
+ ActivityResolution {
735
+ status: Some(cancel.into()),
736
+ }
737
+ }
738
+ }
649
739
  };
740
+
650
741
  let mut responses = vec![
651
742
  MachineResponse::PushWFJob(OutgoingJob {
652
743
  variant: ResolveActivity {
@@ -727,14 +818,14 @@ impl TryFrom<CommandType> for LocalActivityMachineEvents {
727
818
  }
728
819
  }
729
820
 
730
- impl TryFrom<HistoryEvent> for LocalActivityMachineEvents {
821
+ impl TryFrom<HistEventData> for LocalActivityMachineEvents {
731
822
  type Error = WFMachinesError;
732
823
 
733
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
824
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
825
+ let e = e.event;
734
826
  if e.event_type() != EventType::MarkerRecorded {
735
827
  return Err(WFMachinesError::Nondeterminism(format!(
736
- "Local activity machine cannot handle this event: {}",
737
- e
828
+ "Local activity machine cannot handle this event: {e}"
738
829
  )));
739
830
  }
740
831
 
@@ -758,26 +849,30 @@ fn verify_marker_data_matches(
758
849
  dat.marker_dat.seq, shared.attrs.seq
759
850
  )));
760
851
  }
761
-
762
- Ok(())
763
- }
764
-
765
- impl From<LocalActivityExecutionResult> for ActivityResolution {
766
- fn from(lar: LocalActivityExecutionResult) -> Self {
767
- match lar {
768
- LocalActivityExecutionResult::Completed(c) => ActivityResolution {
769
- status: Some(c.into()),
770
- },
771
- LocalActivityExecutionResult::Failed(f) | LocalActivityExecutionResult::TimedOut(f) => {
772
- ActivityResolution {
773
- status: Some(f.into()),
774
- }
775
- }
776
- LocalActivityExecutionResult::Cancelled(cancel) => ActivityResolution {
777
- status: Some(cancel.into()),
778
- },
852
+ // Here we use whether or not we were replaying when we _first invoked_ the LA, because we
853
+ // are always replaying when we see the marker recorded event, and that would make this check
854
+ // a bit pointless.
855
+ if shared.internal_flags.borrow_mut().try_use(
856
+ CoreInternalFlags::IdAndTypeDeterminismChecks,
857
+ !shared.replaying_when_invoked,
858
+ ) {
859
+ if dat.marker_dat.activity_id != shared.attrs.activity_id {
860
+ return Err(WFMachinesError::Nondeterminism(format!(
861
+ "Activity id of recorded marker '{}' does not \
862
+ match activity id of local activity command '{}'",
863
+ dat.marker_dat.activity_id, shared.attrs.activity_id
864
+ )));
865
+ }
866
+ if dat.marker_dat.activity_type != shared.attrs.activity_type {
867
+ return Err(WFMachinesError::Nondeterminism(format!(
868
+ "Activity type of recorded marker '{}' does not \
869
+ match activity type of local activity command '{}'",
870
+ dat.marker_dat.activity_type, shared.attrs.activity_type
871
+ )));
779
872
  }
780
873
  }
874
+
875
+ Ok(())
781
876
  }
782
877
 
783
878
  #[cfg(test)]
@@ -795,15 +890,19 @@ mod tests {
795
890
  coresdk::{
796
891
  activity_result::ActivityExecutionResult,
797
892
  workflow_activation::{workflow_activation_job, WorkflowActivationJob},
798
- workflow_commands::ActivityCancellationType::WaitCancellationCompleted,
799
893
  },
800
894
  temporal::api::{
801
895
  command::v1::command, enums::v1::WorkflowTaskFailedCause, failure::v1::Failure,
802
896
  },
897
+ DEFAULT_ACTIVITY_TYPE,
803
898
  };
804
899
 
805
900
  async fn la_wf(ctx: WfContext) -> WorkflowResult<()> {
806
- ctx.local_activity(LocalActivityOptions::default()).await;
901
+ ctx.local_activity(LocalActivityOptions {
902
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
903
+ ..Default::default()
904
+ })
905
+ .await;
807
906
  Ok(().into())
808
907
  }
809
908
 
@@ -916,8 +1015,16 @@ mod tests {
916
1015
  }
917
1016
 
918
1017
  async fn two_la_wf(ctx: WfContext) -> WorkflowResult<()> {
919
- ctx.local_activity(LocalActivityOptions::default()).await;
920
- ctx.local_activity(LocalActivityOptions::default()).await;
1018
+ ctx.local_activity(LocalActivityOptions {
1019
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1020
+ ..Default::default()
1021
+ })
1022
+ .await;
1023
+ ctx.local_activity(LocalActivityOptions {
1024
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1025
+ ..Default::default()
1026
+ })
1027
+ .await;
921
1028
  Ok(().into())
922
1029
  }
923
1030
 
@@ -1010,8 +1117,14 @@ mod tests {
1010
1117
 
1011
1118
  async fn two_la_wf_parallel(ctx: WfContext) -> WorkflowResult<()> {
1012
1119
  tokio::join!(
1013
- ctx.local_activity(LocalActivityOptions::default()),
1014
- ctx.local_activity(LocalActivityOptions::default())
1120
+ ctx.local_activity(LocalActivityOptions {
1121
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1122
+ ..Default::default()
1123
+ }),
1124
+ ctx.local_activity(LocalActivityOptions {
1125
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1126
+ ..Default::default()
1127
+ })
1015
1128
  );
1016
1129
  Ok(().into())
1017
1130
  }
@@ -1094,9 +1207,17 @@ mod tests {
1094
1207
  }
1095
1208
 
1096
1209
  async fn la_timer_la(ctx: WfContext) -> WorkflowResult<()> {
1097
- ctx.local_activity(LocalActivityOptions::default()).await;
1210
+ ctx.local_activity(LocalActivityOptions {
1211
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1212
+ ..Default::default()
1213
+ })
1214
+ .await;
1098
1215
  ctx.timer(Duration::from_secs(5)).await;
1099
- ctx.local_activity(LocalActivityOptions::default()).await;
1216
+ ctx.local_activity(LocalActivityOptions {
1217
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1218
+ ..Default::default()
1219
+ })
1220
+ .await;
1100
1221
  Ok(().into())
1101
1222
  }
1102
1223
 
@@ -1337,6 +1458,7 @@ mod tests {
1337
1458
  let func = WorkflowFunction::new(move |ctx| async move {
1338
1459
  let la = ctx.local_activity(LocalActivityOptions {
1339
1460
  cancel_type,
1461
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1340
1462
  ..Default::default()
1341
1463
  });
1342
1464
  ctx.timer(Duration::from_secs(1)).await;
@@ -1346,20 +1468,29 @@ mod tests {
1346
1468
  ctx.timer(Duration::from_secs(1)).await;
1347
1469
  let resolution = la.await;
1348
1470
  assert!(resolution.cancelled());
1471
+ let rfail = resolution.unwrap_failure();
1472
+ assert_matches!(
1473
+ rfail.failure_info,
1474
+ Some(FailureInfo::ActivityFailureInfo(_))
1475
+ );
1476
+ assert_matches!(
1477
+ rfail.cause.unwrap().failure_info,
1478
+ Some(FailureInfo::CanceledFailureInfo(_))
1479
+ );
1349
1480
  Ok(().into())
1350
1481
  });
1351
1482
 
1352
1483
  let mut t = TestHistoryBuilder::default();
1353
1484
  t.add_by_type(EventType::WorkflowExecutionStarted);
1354
1485
  t.add_full_wf_task();
1355
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1486
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1356
1487
  t.add_timer_fired(timer_started_event_id, "1".to_string());
1357
1488
  t.add_full_wf_task();
1358
1489
  if cancel_type != ActivityCancellationType::WaitCancellationCompleted {
1359
1490
  // With non-wait cancels, the cancel is immediate
1360
1491
  t.add_local_activity_cancel_marker(1, "1");
1361
1492
  }
1362
- let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
1493
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1363
1494
  if cancel_type == ActivityCancellationType::WaitCancellationCompleted {
1364
1495
  // With wait cancels, the cancel marker is not recorded until activity reports.
1365
1496
  t.add_local_activity_cancel_marker(1, "1");
@@ -1403,8 +1534,9 @@ mod tests {
1403
1534
  assert_eq!(commands[1].command_type, CommandType::StartTimer as i32);
1404
1535
  }
1405
1536
 
1406
- if replay {
1407
- wfm.get_next_activation().await.unwrap()
1537
+ let commands = if replay {
1538
+ wfm.get_next_activation().await.unwrap();
1539
+ wfm.get_server_commands().commands
1408
1540
  } else {
1409
1541
  // On non replay, there's an additional activation, because completing with the cancel
1410
1542
  // wants to wake up the workflow to see if resolving the LA as cancelled did anything.
@@ -1412,7 +1544,7 @@ mod tests {
1412
1544
  // what would have happened if we woke up with new history -- but it does mean we
1413
1545
  // generate the commands at this point. This matters b/c we want to make sure the record
1414
1546
  // marker command is sent as soon as cancel happens.
1415
- if cancel_type == WaitCancellationCompleted {
1547
+ if cancel_type == ActivityCancellationType::WaitCancellationCompleted {
1416
1548
  wfm.complete_local_activity(1, ActivityExecutionResult::cancel_from_details(None))
1417
1549
  .unwrap();
1418
1550
  }
@@ -1429,11 +1561,11 @@ mod tests {
1429
1561
 
1430
1562
  wfm.new_history(t.get_history_info(3).unwrap().into())
1431
1563
  .await
1432
- .unwrap()
1564
+ .unwrap();
1565
+ wfm.get_next_activation().await.unwrap();
1566
+ wfm.get_server_commands().commands
1433
1567
  };
1434
1568
 
1435
- wfm.get_next_activation().await.unwrap();
1436
- let commands = wfm.get_server_commands().commands;
1437
1569
  assert_eq!(commands.len(), 1);
1438
1570
  assert_eq!(
1439
1571
  commands[0].command_type,