@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
@@ -2,7 +2,8 @@ use super::{
2
2
  workflow_machines::MachineResponse, Cancellable, EventInfo, NewMachineWithCommand,
3
3
  OnEventWrapper, WFMachinesAdapter, WFMachinesError,
4
4
  };
5
- use rustfsm::{fsm, MachineError, TransitionResult};
5
+ use crate::worker::workflow::machines::HistEventData;
6
+ use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
6
7
  use std::convert::TryFrom;
7
8
  use temporal_sdk_core_protos::{
8
9
  coresdk::{
@@ -85,10 +86,8 @@ pub(super) fn new_external_signal(
85
86
  Some(sig_we::Target::WorkflowExecution(we)) => (we, false),
86
87
  };
87
88
 
88
- let mut s = SignalExternalMachine {
89
- state: Created {}.into(),
90
- shared_state: SharedState { seq: attrs.seq },
91
- };
89
+ let mut s =
90
+ SignalExternalMachine::from_parts(Created {}.into(), SharedState { seq: attrs.seq });
92
91
  OnEventWrapper::on_event_mut(&mut s, SignalExternalMachineEvents::Schedule)
93
92
  .expect("Scheduling signal external wf command doesn't fail");
94
93
  let cmd_attrs = command::Attributes::SignalExternalWorkflowExecutionCommandAttributes(
@@ -183,10 +182,11 @@ impl TryFrom<CommandType> for SignalExternalMachineEvents {
183
182
  })
184
183
  }
185
184
  }
186
- impl TryFrom<HistoryEvent> for SignalExternalMachineEvents {
185
+ impl TryFrom<HistEventData> for SignalExternalMachineEvents {
187
186
  type Error = WFMachinesError;
188
187
 
189
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
188
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
189
+ let e = e.event;
190
190
  Ok(match e.event_type() {
191
191
  EventType::ExternalWorkflowExecutionSignaled => Self::ExternalWorkflowExecutionSignaled,
192
192
  EventType::SignalExternalWorkflowExecutionInitiated => {
@@ -202,15 +202,13 @@ impl TryFrom<HistoryEvent> for SignalExternalMachineEvents {
202
202
  Self::SignalExternalWorkflowExecutionFailed(attrs.cause())
203
203
  } else {
204
204
  return Err(WFMachinesError::Fatal(format!(
205
- "Signal workflow failed attributes were unset: {}",
206
- e
205
+ "Signal workflow failed attributes were unset: {e}"
207
206
  )));
208
207
  }
209
208
  }
210
209
  _ => {
211
210
  return Err(WFMachinesError::Nondeterminism(format!(
212
- "Signal external WF machine does not handle this event: {}",
213
- e
211
+ "Signal external WF machine does not handle this event: {e}"
214
212
  )))
215
213
  }
216
214
  })
@@ -242,7 +240,7 @@ impl WFMachinesAdapter for SignalExternalMachine {
242
240
  seq: self.shared_state.seq,
243
241
  // TODO: Create new failure type upstream for this
244
242
  failure: Some(Failure {
245
- message: format!("Unable to signal external workflow because {}", reason),
243
+ message: format!("Unable to signal external workflow because {reason}"),
246
244
  failure_info: Some(FailureInfo::ApplicationFailureInfo(
247
245
  ApplicationFailureInfo {
248
246
  r#type: f.to_string(),
@@ -297,7 +295,7 @@ impl Cancellable for SignalExternalMachine {
297
295
  fn was_cancelled_before_sent_to_server(&self) -> bool {
298
296
  // We are only ever in the cancelled state if cancelled before sent to server, there is no
299
297
  // after sent cancellation here.
300
- matches!(self.state, SignalExternalMachineState::Cancelled(_))
298
+ matches!(self.state(), SignalExternalMachineState::Cancelled(_))
301
299
  }
302
300
  }
303
301
 
@@ -427,13 +425,10 @@ mod tests {
427
425
  SignalExternalMachineState::Cancelled(Cancelled {}),
428
426
  Signaled {}.into(),
429
427
  ] {
430
- let mut s = SignalExternalMachine {
431
- state: state.clone(),
432
- shared_state: Default::default(),
433
- };
428
+ let mut s = SignalExternalMachine::from_parts(state.clone(), Default::default());
434
429
  let cmds = s.cancel().unwrap();
435
430
  assert_eq!(cmds.len(), 0);
436
- assert_eq!(discriminant(&state), discriminant(&s.state));
431
+ assert_eq!(discriminant(&state), discriminant(s.state()));
437
432
  }
438
433
  }
439
434
  }
@@ -1,9 +1,10 @@
1
1
  #![allow(clippy::large_enum_variant)]
2
2
 
3
3
  use super::{
4
- workflow_machines::{MachineResponse, WFMachinesError},
5
- Cancellable, EventInfo, NewMachineWithCommand, OnEventWrapper, WFMachinesAdapter,
4
+ workflow_machines::MachineResponse, Cancellable, EventInfo, NewMachineWithCommand,
5
+ OnEventWrapper, WFMachinesAdapter,
6
6
  };
7
+ use crate::worker::workflow::{machines::HistEventData, WFMachinesError};
7
8
  use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
8
9
  use std::convert::TryFrom;
9
10
  use temporal_sdk_core_protos::{
@@ -83,20 +84,21 @@ impl TimerMachine {
83
84
  }
84
85
 
85
86
  fn new(attribs: StartTimer) -> Self {
86
- Self {
87
- state: Created {}.into(),
88
- shared_state: SharedState {
87
+ Self::from_parts(
88
+ Created {}.into(),
89
+ SharedState {
89
90
  attrs: attribs,
90
91
  cancelled_before_sent: false,
91
92
  },
92
- }
93
+ )
93
94
  }
94
95
  }
95
96
 
96
- impl TryFrom<HistoryEvent> for TimerMachineEvents {
97
+ impl TryFrom<HistEventData> for TimerMachineEvents {
97
98
  type Error = WFMachinesError;
98
99
 
99
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
100
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
101
+ let e = e.event;
100
102
  Ok(match e.event_type() {
101
103
  EventType::TimerStarted => Self::TimerStarted(e.event_id),
102
104
  EventType::TimerCanceled => Self::TimerCanceled,
@@ -107,15 +109,13 @@ impl TryFrom<HistoryEvent> for TimerMachineEvents {
107
109
  Self::TimerFired(attrs)
108
110
  } else {
109
111
  return Err(WFMachinesError::Fatal(format!(
110
- "Timer fired attribs were unset: {}",
111
- e
112
+ "Timer fired attribs were unset: {e}"
112
113
  )));
113
114
  }
114
115
  }
115
116
  _ => {
116
117
  return Err(WFMachinesError::Nondeterminism(format!(
117
- "Timer machine does not handle this event: {}",
118
- e
118
+ "Timer machine does not handle this event: {e}"
119
119
  )))
120
120
  }
121
121
  })
@@ -178,15 +178,9 @@ impl StartCommandCreated {
178
178
  TransitionResult::default()
179
179
  }
180
180
 
181
- pub(super) fn on_cancel(self, dat: SharedState) -> TimerMachineTransition<Canceled> {
182
- TransitionResult::ok_shared(
183
- vec![],
184
- Canceled::default(),
185
- SharedState {
186
- cancelled_before_sent: true,
187
- ..dat
188
- },
189
- )
181
+ pub(super) fn on_cancel(self, dat: &mut SharedState) -> TimerMachineTransition<Canceled> {
182
+ dat.cancelled_before_sent = true;
183
+ TransitionResult::default()
190
184
  }
191
185
  }
192
186
 
@@ -196,7 +190,7 @@ pub(super) struct StartCommandRecorded {}
196
190
  impl StartCommandRecorded {
197
191
  pub(super) fn on_timer_fired(
198
192
  self,
199
- dat: SharedState,
193
+ dat: &mut SharedState,
200
194
  attrs: TimerFiredEventAttributes,
201
195
  ) -> TimerMachineTransition<Fired> {
202
196
  if dat.attrs.seq.to_string() == attrs.timer_id {
@@ -211,7 +205,7 @@ impl StartCommandRecorded {
211
205
 
212
206
  pub(super) fn on_cancel(
213
207
  self,
214
- dat: SharedState,
208
+ dat: &mut SharedState,
215
209
  ) -> TimerMachineTransition<CancelTimerCommandCreated> {
216
210
  let cmd = Command {
217
211
  command_type: CommandType::CancelTimer as i32,
@@ -256,7 +250,7 @@ impl Cancellable for TimerMachine {
256
250
  vec![MachineResponse::IssueNewCommand(cmd)]
257
251
  }
258
252
  None => vec![],
259
- x => panic!("Invalid cancel event response {:?}", x),
253
+ x => panic!("Invalid cancel event response {x:?}"),
260
254
  },
261
255
  )
262
256
  }
@@ -423,13 +417,10 @@ mod test {
423
417
  #[test]
424
418
  fn cancels_ignored_terminal() {
425
419
  for state in [TimerMachineState::Canceled(Canceled {}), Fired {}.into()] {
426
- let mut s = TimerMachine {
427
- state: state.clone(),
428
- shared_state: Default::default(),
429
- };
420
+ let mut s = TimerMachine::from_parts(state.clone(), Default::default());
430
421
  let cmds = s.cancel().unwrap();
431
422
  assert_eq!(cmds.len(), 0);
432
- assert_eq!(discriminant(&state), discriminant(&s.state));
423
+ assert_eq!(discriminant(&state), discriminant(s.state()));
433
424
  }
434
425
  }
435
426
  }
@@ -144,7 +144,7 @@ mod machine_coverage_report {
144
144
  m @ "ModifyWorkflowPropertiesMachine" => {
145
145
  cover_transitions(m, &mut modify_wf_props, coverage)
146
146
  }
147
- m => panic!("Unknown machine {}", m),
147
+ m => panic!("Unknown machine {m}"),
148
148
  }
149
149
  }
150
150
  }
@@ -168,7 +168,7 @@ mod machine_coverage_report {
168
168
  let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
169
169
  d.push("machine_coverage");
170
170
  std::fs::create_dir_all(&d).unwrap();
171
- d.push(format!("{}_Coverage.puml", machine));
171
+ d.push(format!("{machine}_Coverage.puml"));
172
172
  let mut file = File::create(d).unwrap();
173
173
  file.write_all(viz.as_bytes()).unwrap();
174
174
  }
@@ -1,18 +1,28 @@
1
- use super::{
2
- workflow_machines::{MachineResponse, WFMachinesError},
3
- NewMachineWithCommand,
1
+ use super::{workflow_machines::MachineResponse, NewMachineWithCommand};
2
+ use crate::{
3
+ internal_flags::CoreInternalFlags,
4
+ worker::workflow::{
5
+ machines::{
6
+ patch_state_machine::VERSION_SEARCH_ATTR_KEY, Cancellable, EventInfo, HistEventData,
7
+ WFMachinesAdapter,
8
+ },
9
+ InternalFlagsRef, WFMachinesError,
10
+ },
4
11
  };
5
- use crate::worker::workflow::machines::{Cancellable, EventInfo, WFMachinesAdapter};
6
- use rustfsm::{fsm, TransitionResult};
12
+ use rustfsm::{fsm, StateMachine, TransitionResult};
7
13
  use temporal_sdk_core_protos::{
8
14
  coresdk::workflow_commands::UpsertWorkflowSearchAttributes,
9
15
  temporal::api::{
10
- command::v1::Command,
16
+ command::v1::{command, Command, UpsertWorkflowSearchAttributesCommandAttributes},
17
+ common::v1::SearchAttributes,
11
18
  enums::v1::{CommandType, EventType},
12
- history::v1::HistoryEvent,
19
+ history::v1::{history_event, HistoryEvent},
13
20
  },
14
21
  };
15
22
 
23
+ /// By default the server permits SA values under 2k.
24
+ pub(crate) const MAX_SEARCH_ATTR_PAYLOAD_SIZE: usize = 2048;
25
+
16
26
  fsm! {
17
27
  pub(super) name UpsertSearchAttributesMachine;
18
28
  command UpsertSearchAttributesMachineCommand;
@@ -28,18 +38,70 @@ fsm! {
28
38
  // upon observing a history event indicating that the command has been recorded. Note that this
29
39
  // does not imply that the command has been _executed_, only that it _will be_ executed at some
30
40
  // point in the future.
31
- CommandIssued --(CommandRecorded) --> Done;
41
+ CommandIssued --(CommandRecorded(CmdRecDat), shared on_command_recorded) --> Done;
32
42
  }
33
43
 
34
44
  /// Instantiates an UpsertSearchAttributesMachine and packs it together with an initial command
35
45
  /// to apply the provided search attribute update.
36
46
  pub(super) fn upsert_search_attrs(
37
47
  attribs: UpsertWorkflowSearchAttributes,
48
+ internal_flags: InternalFlagsRef,
49
+ replaying: bool,
50
+ ) -> NewMachineWithCommand {
51
+ let has_flag = internal_flags
52
+ .borrow_mut()
53
+ .try_use(CoreInternalFlags::UpsertSearchAttributeOnPatch, !replaying);
54
+ if has_flag
55
+ && attribs
56
+ .search_attributes
57
+ .contains_key(VERSION_SEARCH_ATTR_KEY)
58
+ {
59
+ warn!(
60
+ "Upserting the {VERSION_SEARCH_ATTR_KEY} search attribute directly from workflow code \
61
+ is not permitted and has no effect!"
62
+ );
63
+ // We must still create the command to preserve compatability with anyone previously doing
64
+ // this.
65
+ create_new(Default::default(), true, internal_flags)
66
+ } else {
67
+ create_new(attribs.search_attributes.into(), false, internal_flags)
68
+ }
69
+ }
70
+
71
+ /// May be used by other state machines / internal needs which desire upserting search attributes.
72
+ pub(super) fn upsert_search_attrs_internal(
73
+ attribs: UpsertWorkflowSearchAttributesCommandAttributes,
74
+ internal_flags: InternalFlagsRef,
38
75
  ) -> NewMachineWithCommand {
39
- let sm = UpsertSearchAttributesMachine::new();
76
+ create_new(
77
+ attribs.search_attributes.unwrap_or_default(),
78
+ true,
79
+ internal_flags,
80
+ )
81
+ }
82
+
83
+ fn create_new(
84
+ sa_map: SearchAttributes,
85
+ should_skip_determinism: bool,
86
+ internal_flags: InternalFlagsRef,
87
+ ) -> NewMachineWithCommand {
88
+ let sm = UpsertSearchAttributesMachine::from_parts(
89
+ Created {}.into(),
90
+ SharedState {
91
+ sa_map: sa_map.clone(),
92
+ should_skip_determinism,
93
+ internal_flags,
94
+ },
95
+ );
40
96
  let cmd = Command {
41
97
  command_type: CommandType::UpsertWorkflowSearchAttributes as i32,
42
- attributes: Some(attribs.into()),
98
+ attributes: Some(
99
+ command::Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
100
+ UpsertWorkflowSearchAttributesCommandAttributes {
101
+ search_attributes: Some(sa_map),
102
+ },
103
+ ),
104
+ ),
43
105
  };
44
106
  NewMachineWithCommand {
45
107
  command: cmd,
@@ -47,8 +109,12 @@ pub(super) fn upsert_search_attrs(
47
109
  }
48
110
  }
49
111
 
50
- /// Unused but must exist
51
- type SharedState = ();
112
+ #[derive(Clone)]
113
+ pub(super) struct SharedState {
114
+ should_skip_determinism: bool,
115
+ sa_map: SearchAttributes,
116
+ internal_flags: InternalFlagsRef,
117
+ }
52
118
 
53
119
  /// The state-machine-specific set of commands that are the results of state transition in the
54
120
  /// UpsertSearchAttributesMachine. There are none of these because this state machine emits the
@@ -65,21 +131,39 @@ pub(super) struct Created {}
65
131
  /// higher-level machinery, it transitions into this state.
66
132
  #[derive(Debug, Default, Clone, derive_more::Display)]
67
133
  pub(super) struct CommandIssued {}
134
+ pub(super) struct CmdRecDat {
135
+ sa_map: Option<SearchAttributes>,
136
+ replaying: bool,
137
+ }
138
+
139
+ impl CommandIssued {
140
+ pub(super) fn on_command_recorded(
141
+ self,
142
+ shared: &mut SharedState,
143
+ dat: CmdRecDat,
144
+ ) -> UpsertSearchAttributesMachineTransition<Done> {
145
+ if shared.internal_flags.borrow_mut().try_use(
146
+ CoreInternalFlags::UpsertSearchAttributeOnPatch,
147
+ !dat.replaying,
148
+ ) {
149
+ let sa = dat.sa_map.unwrap_or_default();
150
+ if !shared.should_skip_determinism && shared.sa_map != sa {
151
+ return TransitionResult::Err(WFMachinesError::Nondeterminism(format!(
152
+ "Search attribute upsert calls must remain deterministic, but {:?} does not \
153
+ match the attributes from history: {:?}",
154
+ shared.sa_map, sa
155
+ )));
156
+ }
157
+ }
158
+ TransitionResult::default()
159
+ }
160
+ }
68
161
 
69
162
  /// Once the server has recorded its receipt of the search attribute update, the
70
163
  /// UpsertSearchAttributesMachine transitions into this terminal state.
71
164
  #[derive(Debug, Default, Clone, derive_more::Display)]
72
165
  pub(super) struct Done {}
73
166
 
74
- impl UpsertSearchAttributesMachine {
75
- fn new() -> Self {
76
- Self {
77
- state: Created {}.into(),
78
- shared_state: (),
79
- }
80
- }
81
- }
82
-
83
167
  impl WFMachinesAdapter for UpsertSearchAttributesMachine {
84
168
  /// Transforms an UpsertSearchAttributesMachine-specific command (i.e. an instance of the type
85
169
  /// UpsertSearchAttributesMachineCommand) to a more generic form supported by the abstract
@@ -109,14 +193,19 @@ impl Cancellable for UpsertSearchAttributesMachine {}
109
193
  // Converts the generic history event with type EventType::UpsertWorkflowSearchAttributes into the
110
194
  // UpsertSearchAttributesMachine-specific event type
111
195
  // UpsertSearchAttributesMachineEvents::CommandRecorded.
112
- impl TryFrom<HistoryEvent> for UpsertSearchAttributesMachineEvents {
196
+ impl TryFrom<HistEventData> for UpsertSearchAttributesMachineEvents {
113
197
  type Error = WFMachinesError;
114
198
 
115
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
116
- match e.event_type() {
117
- EventType::UpsertWorkflowSearchAttributes => {
118
- Ok(UpsertSearchAttributesMachineEvents::CommandRecorded)
119
- }
199
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
200
+ match e.event.attributes {
201
+ Some(history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(
202
+ attrs,
203
+ )) => Ok(UpsertSearchAttributesMachineEvents::CommandRecorded(
204
+ CmdRecDat {
205
+ sa_map: attrs.search_attributes,
206
+ replaying: e.replaying,
207
+ },
208
+ )),
120
209
  _ => Err(Self::Error::Nondeterminism(format!(
121
210
  "UpsertWorkflowSearchAttributesMachine does not handle {e}"
122
211
  ))),
@@ -141,13 +230,6 @@ impl TryFrom<CommandType> for UpsertSearchAttributesMachineEvents {
141
230
  }
142
231
  }
143
232
 
144
- // There is no Command/Response associated with this transition
145
- impl From<CommandIssued> for Done {
146
- fn from(_: CommandIssued) -> Self {
147
- Self {}
148
- }
149
- }
150
-
151
233
  // There is no Command/Response associated with this transition
152
234
  impl From<Created> for CommandIssued {
153
235
  fn from(_: Created) -> Self {
@@ -158,12 +240,30 @@ impl From<Created> for CommandIssued {
158
240
  #[cfg(test)]
159
241
  mod tests {
160
242
  use super::{super::OnEventWrapper, *};
161
- use crate::{replay::TestHistoryBuilder, worker::workflow::ManagedWFFunc};
162
- use rustfsm::StateMachine;
243
+ use crate::{
244
+ internal_flags::InternalFlags,
245
+ replay::TestHistoryBuilder,
246
+ test_help::{build_mock_pollers, mock_worker, MockPollCfg, ResponseType},
247
+ worker::{
248
+ client::mocks::mock_workflow_client,
249
+ workflow::{machines::patch_state_machine::VERSION_SEARCH_ATTR_KEY, ManagedWFFunc},
250
+ },
251
+ };
252
+ use rustfsm::{MachineError, StateMachine};
253
+ use std::{cell::RefCell, collections::HashMap, rc::Rc};
163
254
  use temporal_sdk::{WfContext, WorkflowFunction};
164
- use temporal_sdk_core_protos::temporal::api::{
165
- command::v1::command::Attributes, common::v1::Payload,
255
+ use temporal_sdk_core_api::Worker;
256
+ use temporal_sdk_core_protos::{
257
+ coresdk::{
258
+ workflow_commands::SetPatchMarker, workflow_completion::WorkflowActivationCompletion,
259
+ AsJsonPayloadExt,
260
+ },
261
+ temporal::api::{
262
+ command::v1::command::Attributes, common::v1::Payload,
263
+ history::v1::UpsertWorkflowSearchAttributesEventAttributes,
264
+ },
166
265
  };
266
+ use temporal_sdk_core_test_utils::WorkerTestHelpers;
167
267
 
168
268
  #[tokio::test]
169
269
  async fn upsert_search_attrs_from_workflow() {
@@ -216,27 +316,133 @@ mod tests {
216
316
  wfm.shutdown().await.unwrap();
217
317
  }
218
318
 
219
- #[tokio::test]
220
- async fn upsert_search_attrs_sm() {
221
- let mut sm = UpsertSearchAttributesMachine::new();
222
- assert_eq!(Created {}.to_string(), sm.state().to_string());
319
+ #[rstest::rstest]
320
+ fn upsert_search_attrs_sm(#[values(true, false)] nondetermistic: bool) {
321
+ let mut sm = UpsertSearchAttributesMachine::from_parts(
322
+ Created {}.into(),
323
+ SharedState {
324
+ sa_map: Default::default(),
325
+ should_skip_determinism: false,
326
+ internal_flags: Rc::new(RefCell::new(InternalFlags::all_core_enabled())),
327
+ },
328
+ );
223
329
 
224
- let cmd_scheduled_sm_event = CommandType::UpsertWorkflowSearchAttributes
225
- .try_into()
226
- .unwrap();
330
+ let sa_attribs = if nondetermistic {
331
+ UpsertWorkflowSearchAttributesEventAttributes {
332
+ workflow_task_completed_event_id: 0,
333
+ search_attributes: Some(SearchAttributes {
334
+ indexed_fields: HashMap::from([("Yo".to_string(), Payload::default())]),
335
+ }),
336
+ }
337
+ } else {
338
+ Default::default()
339
+ };
227
340
  let recorded_history_event = HistoryEvent {
228
341
  event_type: EventType::UpsertWorkflowSearchAttributes as i32,
342
+ attributes: Some(
343
+ history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(
344
+ sa_attribs,
345
+ ),
346
+ ),
229
347
  ..Default::default()
230
348
  };
231
349
  assert!(sm.matches_event(&recorded_history_event));
232
- let cmd_recorded_sm_event = recorded_history_event.try_into().unwrap();
350
+ let cmd_recorded_sm_event = HistEventData {
351
+ event: recorded_history_event,
352
+ replaying: false,
353
+ current_task_is_last_in_history: true,
354
+ }
355
+ .try_into()
356
+ .unwrap();
233
357
 
234
- OnEventWrapper::on_event_mut(&mut sm, cmd_scheduled_sm_event)
235
- .expect("CommandScheduled should transition Created -> CommandIssued");
358
+ OnEventWrapper::on_event_mut(
359
+ &mut sm,
360
+ CommandType::UpsertWorkflowSearchAttributes
361
+ .try_into()
362
+ .unwrap(),
363
+ )
364
+ .expect("CommandScheduled should transition Created -> CommandIssued");
236
365
  assert_eq!(CommandIssued {}.to_string(), sm.state().to_string());
237
366
 
238
- OnEventWrapper::on_event_mut(&mut sm, cmd_recorded_sm_event)
239
- .expect("CommandRecorded should transition CommandIssued -> Done");
240
- assert_eq!(Done {}.to_string(), sm.state().to_string());
367
+ let recorded_res = OnEventWrapper::on_event_mut(&mut sm, cmd_recorded_sm_event);
368
+ if nondetermistic {
369
+ assert_matches!(
370
+ recorded_res.unwrap_err(),
371
+ MachineError::Underlying(WFMachinesError::Nondeterminism(_))
372
+ );
373
+ } else {
374
+ recorded_res.expect("CommandRecorded should transition CommandIssued -> Done");
375
+ assert_eq!(Done {}.to_string(), sm.state().to_string());
376
+ }
377
+ }
378
+
379
+ #[rstest::rstest]
380
+ #[tokio::test]
381
+ async fn upserting_change_version_directly(
382
+ #[values(true, false)] flag_in_history: bool,
383
+ #[values(true, false)] with_patched_cmd: bool,
384
+ ) {
385
+ let patch_id = "whatever".to_string();
386
+ let mut t = TestHistoryBuilder::default();
387
+ t.add_by_type(EventType::WorkflowExecutionStarted);
388
+ t.add_full_wf_task();
389
+ if flag_in_history {
390
+ t.set_flags_first_wft(
391
+ &[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
392
+ &[],
393
+ );
394
+ }
395
+ if with_patched_cmd {
396
+ t.add_has_change_marker(&patch_id, false);
397
+ }
398
+ t.add_upsert_search_attrs_for_patch(&[patch_id.clone()]);
399
+ t.add_full_wf_task();
400
+ t.add_workflow_execution_completed();
401
+
402
+ let mut mp = MockPollCfg::from_resp_batches(
403
+ "fakeid",
404
+ t,
405
+ [ResponseType::ToTaskNum(1), ResponseType::AllHistory],
406
+ mock_workflow_client(),
407
+ );
408
+ // Ensure the upsert command has an empty map when not using the patched command
409
+ if !with_patched_cmd {
410
+ mp.completion_asserts = Some(Box::new(|wftc| {
411
+ assert_matches!(wftc.commands.get(0).and_then(|c| c.attributes.as_ref()).unwrap(),
412
+ Attributes::UpsertWorkflowSearchAttributesCommandAttributes(attrs)
413
+ if attrs.search_attributes.as_ref().unwrap().indexed_fields.is_empty())
414
+ }));
415
+ }
416
+ let core = mock_worker(build_mock_pollers(mp));
417
+
418
+ let mut ver_upsert = HashMap::new();
419
+ ver_upsert.insert(
420
+ VERSION_SEARCH_ATTR_KEY.to_string(),
421
+ "hi".as_json_payload().unwrap(),
422
+ );
423
+ let act = core.poll_workflow_activation().await.unwrap();
424
+ let mut cmds = if with_patched_cmd {
425
+ vec![SetPatchMarker {
426
+ patch_id,
427
+ deprecated: false,
428
+ }
429
+ .into()]
430
+ } else {
431
+ vec![]
432
+ };
433
+ cmds.push(
434
+ UpsertWorkflowSearchAttributes {
435
+ search_attributes: ver_upsert,
436
+ }
437
+ .into(),
438
+ );
439
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
440
+ act.run_id, cmds,
441
+ ))
442
+ .await
443
+ .unwrap();
444
+ // Now ensure that encountering the upsert in history works fine
445
+ let act = core.poll_workflow_activation().await.unwrap();
446
+ core.complete_execution(&act.run_id).await;
241
447
  }
242
448
  }
@@ -1,15 +1,13 @@
1
- use super::super::{local_activity_state_machine::ResolveDat, WFMachinesError};
1
+ use super::super::local_activity_state_machine::ResolveDat;
2
2
  use crate::{
3
- protosext::{HistoryEventExt, ValidScheduleLA},
3
+ protosext::{CompleteLocalActivityData, ValidScheduleLA},
4
4
  worker::{ExecutingLAId, LocalActRequest, NewLocalAct},
5
5
  };
6
6
  use std::{
7
7
  collections::{HashMap, HashSet},
8
8
  time::SystemTime,
9
9
  };
10
- use temporal_sdk_core_protos::temporal::api::{
11
- common::v1::WorkflowExecution, history::v1::HistoryEvent,
12
- };
10
+ use temporal_sdk_core_protos::temporal::api::common::v1::WorkflowExecution;
13
11
 
14
12
  #[derive(Default)]
15
13
  pub(super) struct LocalActivityData {
@@ -53,7 +51,7 @@ impl LocalActivityData {
53
51
  .chain(self.new_requests.drain(..).map(|sa| {
54
52
  self.executing.insert(sa.seq);
55
53
  LocalActRequest::New(NewLocalAct {
56
- schedule_time: sa.original_schedule_time.unwrap_or_else(SystemTime::now),
54
+ schedule_time: SystemTime::now(),
57
55
  schedule_cmd: sa,
58
56
  workflow_type: wf_type.to_string(),
59
57
  workflow_exec_info: WorkflowExecution {
@@ -70,17 +68,8 @@ impl LocalActivityData {
70
68
  self.executing.len() + self.new_requests.len()
71
69
  }
72
70
 
73
- pub(super) fn process_peekahead_marker(&mut self, e: &HistoryEvent) -> super::Result<()> {
74
- if let Some(la_dat) = e.clone().into_local_activity_marker_details() {
75
- self.preresolutions
76
- .insert(la_dat.marker_dat.seq, la_dat.into());
77
- } else {
78
- return Err(WFMachinesError::Fatal(format!(
79
- "Local activity marker was unparsable: {:?}",
80
- e
81
- )));
82
- }
83
- Ok(())
71
+ pub(super) fn insert_peeked_marker(&mut self, dat: CompleteLocalActivityData) {
72
+ self.preresolutions.insert(dat.marker_dat.seq, dat.into());
84
73
  }
85
74
 
86
75
  pub(super) fn take_preresolution(&mut self, seq: u32) -> Option<ResolveDat> {