@temporalio/core-bridge 1.6.0 → 1.7.1

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 (138) hide show
  1. package/Cargo.lock +520 -456
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +8 -3
  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 +1 -1
  13. package/sdk-core/.github/workflows/heavy.yml +1 -0
  14. package/sdk-core/README.md +13 -7
  15. package/sdk-core/client/src/lib.rs +27 -9
  16. package/sdk-core/client/src/metrics.rs +17 -8
  17. package/sdk-core/client/src/raw.rs +3 -3
  18. package/sdk-core/core/Cargo.toml +3 -4
  19. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  20. package/sdk-core/core/src/abstractions.rs +197 -18
  21. package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
  22. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  23. package/sdk-core/core/src/core_tests/determinism.rs +212 -2
  24. package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
  25. package/sdk-core/core/src/core_tests/queries.rs +32 -14
  26. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  27. package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
  28. package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
  29. package/sdk-core/core/src/internal_flags.rs +141 -0
  30. package/sdk-core/core/src/lib.rs +14 -9
  31. package/sdk-core/core/src/replay/mod.rs +16 -27
  32. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  33. package/sdk-core/core/src/telemetry/mod.rs +38 -14
  34. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  35. package/sdk-core/core/src/test_help/mod.rs +65 -13
  36. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  37. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  38. package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
  39. package/sdk-core/core/src/worker/activities.rs +347 -173
  40. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  41. package/sdk-core/core/src/worker/client.rs +18 -2
  42. package/sdk-core/core/src/worker/mod.rs +137 -44
  43. package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
  44. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
  45. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
  46. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
  47. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
  48. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
  49. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
  50. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
  51. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
  52. package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
  53. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
  54. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
  55. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
  56. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
  57. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
  58. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
  59. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
  60. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
  61. package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
  62. package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
  63. package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
  64. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
  65. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
  66. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
  67. package/sdk-core/core-api/Cargo.toml +0 -1
  68. package/sdk-core/core-api/src/lib.rs +13 -7
  69. package/sdk-core/core-api/src/telemetry.rs +4 -6
  70. package/sdk-core/core-api/src/worker.rs +5 -0
  71. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
  72. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
  73. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  74. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  75. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  76. package/sdk-core/protos/api_upstream/Makefile +1 -1
  77. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  78. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  80. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  81. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  83. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  84. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  85. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  86. package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  87. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  88. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  89. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  90. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  91. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  92. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  93. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  94. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  95. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  96. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  97. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
  98. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  99. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  100. package/sdk-core/sdk/Cargo.toml +1 -1
  101. package/sdk-core/sdk/src/lib.rs +21 -5
  102. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  103. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  104. package/sdk-core/sdk/src/workflow_future.rs +9 -3
  105. package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
  106. package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
  107. package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
  108. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  109. package/sdk-core/test-utils/src/lib.rs +32 -5
  110. package/sdk-core/tests/heavy_tests.rs +10 -43
  111. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
  115. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
  116. package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
  117. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
  118. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
  120. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  121. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
  122. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
  123. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
  124. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  125. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
  126. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
  127. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
  129. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
  130. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
  131. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
  132. package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
  133. package/sdk-core/tests/main.rs +16 -25
  134. package/sdk-core/tests/runner.rs +11 -9
  135. package/src/conversions.rs +14 -8
  136. package/src/runtime.rs +9 -8
  137. package/ts/index.ts +8 -6
  138. package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
@@ -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 => {
@@ -295,7 +295,7 @@ impl Cancellable for SignalExternalMachine {
295
295
  fn was_cancelled_before_sent_to_server(&self) -> bool {
296
296
  // We are only ever in the cancelled state if cancelled before sent to server, there is no
297
297
  // after sent cancellation here.
298
- matches!(self.state, SignalExternalMachineState::Cancelled(_))
298
+ matches!(self.state(), SignalExternalMachineState::Cancelled(_))
299
299
  }
300
300
  }
301
301
 
@@ -425,13 +425,10 @@ mod tests {
425
425
  SignalExternalMachineState::Cancelled(Cancelled {}),
426
426
  Signaled {}.into(),
427
427
  ] {
428
- let mut s = SignalExternalMachine {
429
- state: state.clone(),
430
- shared_state: Default::default(),
431
- };
428
+ let mut s = SignalExternalMachine::from_parts(state.clone(), Default::default());
432
429
  let cmds = s.cancel().unwrap();
433
430
  assert_eq!(cmds.len(), 0);
434
- assert_eq!(discriminant(&state), discriminant(&s.state));
431
+ assert_eq!(discriminant(&state), discriminant(s.state()));
435
432
  }
436
433
  }
437
434
  }
@@ -4,7 +4,7 @@ use super::{
4
4
  workflow_machines::MachineResponse, Cancellable, EventInfo, NewMachineWithCommand,
5
5
  OnEventWrapper, WFMachinesAdapter,
6
6
  };
7
- use crate::worker::workflow::WFMachinesError;
7
+ use crate::worker::workflow::{machines::HistEventData, WFMachinesError};
8
8
  use rustfsm::{fsm, MachineError, StateMachine, TransitionResult};
9
9
  use std::convert::TryFrom;
10
10
  use temporal_sdk_core_protos::{
@@ -84,20 +84,21 @@ impl TimerMachine {
84
84
  }
85
85
 
86
86
  fn new(attribs: StartTimer) -> Self {
87
- Self {
88
- state: Created {}.into(),
89
- shared_state: SharedState {
87
+ Self::from_parts(
88
+ Created {}.into(),
89
+ SharedState {
90
90
  attrs: attribs,
91
91
  cancelled_before_sent: false,
92
92
  },
93
- }
93
+ )
94
94
  }
95
95
  }
96
96
 
97
- impl TryFrom<HistoryEvent> for TimerMachineEvents {
97
+ impl TryFrom<HistEventData> for TimerMachineEvents {
98
98
  type Error = WFMachinesError;
99
99
 
100
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
100
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
101
+ let e = e.event;
101
102
  Ok(match e.event_type() {
102
103
  EventType::TimerStarted => Self::TimerStarted(e.event_id),
103
104
  EventType::TimerCanceled => Self::TimerCanceled,
@@ -177,15 +178,9 @@ impl StartCommandCreated {
177
178
  TransitionResult::default()
178
179
  }
179
180
 
180
- pub(super) fn on_cancel(self, dat: SharedState) -> TimerMachineTransition<Canceled> {
181
- TransitionResult::ok_shared(
182
- vec![],
183
- Canceled::default(),
184
- SharedState {
185
- cancelled_before_sent: true,
186
- ..dat
187
- },
188
- )
181
+ pub(super) fn on_cancel(self, dat: &mut SharedState) -> TimerMachineTransition<Canceled> {
182
+ dat.cancelled_before_sent = true;
183
+ TransitionResult::default()
189
184
  }
190
185
  }
191
186
 
@@ -195,7 +190,7 @@ pub(super) struct StartCommandRecorded {}
195
190
  impl StartCommandRecorded {
196
191
  pub(super) fn on_timer_fired(
197
192
  self,
198
- dat: SharedState,
193
+ dat: &mut SharedState,
199
194
  attrs: TimerFiredEventAttributes,
200
195
  ) -> TimerMachineTransition<Fired> {
201
196
  if dat.attrs.seq.to_string() == attrs.timer_id {
@@ -210,7 +205,7 @@ impl StartCommandRecorded {
210
205
 
211
206
  pub(super) fn on_cancel(
212
207
  self,
213
- dat: SharedState,
208
+ dat: &mut SharedState,
214
209
  ) -> TimerMachineTransition<CancelTimerCommandCreated> {
215
210
  let cmd = Command {
216
211
  command_type: CommandType::CancelTimer as i32,
@@ -422,13 +417,10 @@ mod test {
422
417
  #[test]
423
418
  fn cancels_ignored_terminal() {
424
419
  for state in [TimerMachineState::Canceled(Canceled {}), Fired {}.into()] {
425
- let mut s = TimerMachine {
426
- state: state.clone(),
427
- shared_state: Default::default(),
428
- };
420
+ let mut s = TimerMachine::from_parts(state.clone(), Default::default());
429
421
  let cmds = s.cancel().unwrap();
430
422
  assert_eq!(cmds.len(), 0);
431
- assert_eq!(discriminant(&state), discriminant(&s.state));
423
+ assert_eq!(discriminant(&state), discriminant(s.state()));
432
424
  }
433
425
  }
434
426
  }
@@ -1,18 +1,28 @@
1
1
  use super::{workflow_machines::MachineResponse, NewMachineWithCommand};
2
- use crate::worker::workflow::{
3
- machines::{Cancellable, EventInfo, WFMachinesAdapter},
4
- WFMachinesError,
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
+ },
5
11
  };
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,54 @@ 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, 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())
66
+ } else {
67
+ create_new(attribs.search_attributes.into())
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,
38
74
  ) -> NewMachineWithCommand {
39
- let sm = UpsertSearchAttributesMachine::new();
75
+ create_new(attribs.search_attributes.unwrap_or_default())
76
+ }
77
+
78
+ fn create_new(sa_map: SearchAttributes) -> NewMachineWithCommand {
79
+ let sm = UpsertSearchAttributesMachine::from_parts(Created {}.into(), SharedState {});
40
80
  let cmd = Command {
41
81
  command_type: CommandType::UpsertWorkflowSearchAttributes as i32,
42
- attributes: Some(attribs.into()),
82
+ attributes: Some(
83
+ command::Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
84
+ UpsertWorkflowSearchAttributesCommandAttributes {
85
+ search_attributes: Some(sa_map),
86
+ },
87
+ ),
88
+ ),
43
89
  };
44
90
  NewMachineWithCommand {
45
91
  command: cmd,
@@ -47,8 +93,8 @@ pub(super) fn upsert_search_attrs(
47
93
  }
48
94
  }
49
95
 
50
- /// Unused but must exist
51
- type SharedState = ();
96
+ #[derive(Clone)]
97
+ pub(super) struct SharedState {}
52
98
 
53
99
  /// The state-machine-specific set of commands that are the results of state transition in the
54
100
  /// UpsertSearchAttributesMachine. There are none of these because this state machine emits the
@@ -66,20 +112,17 @@ pub(super) struct Created {}
66
112
  #[derive(Debug, Default, Clone, derive_more::Display)]
67
113
  pub(super) struct CommandIssued {}
68
114
 
115
+ impl CommandIssued {
116
+ pub(super) fn on_command_recorded(self) -> UpsertSearchAttributesMachineTransition<Done> {
117
+ TransitionResult::default()
118
+ }
119
+ }
120
+
69
121
  /// Once the server has recorded its receipt of the search attribute update, the
70
122
  /// UpsertSearchAttributesMachine transitions into this terminal state.
71
123
  #[derive(Debug, Default, Clone, derive_more::Display)]
72
124
  pub(super) struct Done {}
73
125
 
74
- impl UpsertSearchAttributesMachine {
75
- fn new() -> Self {
76
- Self {
77
- state: Created {}.into(),
78
- shared_state: (),
79
- }
80
- }
81
- }
82
-
83
126
  impl WFMachinesAdapter for UpsertSearchAttributesMachine {
84
127
  /// Transforms an UpsertSearchAttributesMachine-specific command (i.e. an instance of the type
85
128
  /// UpsertSearchAttributesMachineCommand) to a more generic form supported by the abstract
@@ -109,12 +152,12 @@ impl Cancellable for UpsertSearchAttributesMachine {}
109
152
  // Converts the generic history event with type EventType::UpsertWorkflowSearchAttributes into the
110
153
  // UpsertSearchAttributesMachine-specific event type
111
154
  // UpsertSearchAttributesMachineEvents::CommandRecorded.
112
- impl TryFrom<HistoryEvent> for UpsertSearchAttributesMachineEvents {
155
+ impl TryFrom<HistEventData> for UpsertSearchAttributesMachineEvents {
113
156
  type Error = WFMachinesError;
114
157
 
115
- fn try_from(e: HistoryEvent) -> Result<Self, Self::Error> {
116
- match e.event_type() {
117
- EventType::UpsertWorkflowSearchAttributes => {
158
+ fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
159
+ match e.event.attributes {
160
+ Some(history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(_)) => {
118
161
  Ok(UpsertSearchAttributesMachineEvents::CommandRecorded)
119
162
  }
120
163
  _ => Err(Self::Error::Nondeterminism(format!(
@@ -141,13 +184,6 @@ impl TryFrom<CommandType> for UpsertSearchAttributesMachineEvents {
141
184
  }
142
185
  }
143
186
 
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
187
  // There is no Command/Response associated with this transition
152
188
  impl From<Created> for CommandIssued {
153
189
  fn from(_: Created) -> Self {
@@ -158,12 +194,29 @@ impl From<Created> for CommandIssued {
158
194
  #[cfg(test)]
159
195
  mod tests {
160
196
  use super::{super::OnEventWrapper, *};
161
- use crate::{replay::TestHistoryBuilder, worker::workflow::ManagedWFFunc};
197
+ use crate::{
198
+ replay::TestHistoryBuilder,
199
+ test_help::{build_mock_pollers, mock_worker, MockPollCfg, ResponseType},
200
+ worker::{
201
+ client::mocks::mock_workflow_client,
202
+ workflow::{machines::patch_state_machine::VERSION_SEARCH_ATTR_KEY, ManagedWFFunc},
203
+ },
204
+ };
162
205
  use rustfsm::StateMachine;
206
+ use std::collections::HashMap;
163
207
  use temporal_sdk::{WfContext, WorkflowFunction};
164
- use temporal_sdk_core_protos::temporal::api::{
165
- command::v1::command::Attributes, common::v1::Payload,
208
+ use temporal_sdk_core_api::Worker;
209
+ use temporal_sdk_core_protos::{
210
+ coresdk::{
211
+ workflow_commands::SetPatchMarker, workflow_completion::WorkflowActivationCompletion,
212
+ AsJsonPayloadExt,
213
+ },
214
+ temporal::api::{
215
+ command::v1::command::Attributes, common::v1::Payload,
216
+ history::v1::UpsertWorkflowSearchAttributesEventAttributes,
217
+ },
166
218
  };
219
+ use temporal_sdk_core_test_utils::WorkerTestHelpers;
167
220
 
168
221
  #[tokio::test]
169
222
  async fn upsert_search_attrs_from_workflow() {
@@ -216,27 +269,115 @@ mod tests {
216
269
  wfm.shutdown().await.unwrap();
217
270
  }
218
271
 
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());
272
+ #[rstest::rstest]
273
+ fn upsert_search_attrs_sm() {
274
+ let mut sm = UpsertSearchAttributesMachine::from_parts(Created {}.into(), SharedState {});
223
275
 
224
- let cmd_scheduled_sm_event = CommandType::UpsertWorkflowSearchAttributes
225
- .try_into()
226
- .unwrap();
276
+ let sa_attribs = UpsertWorkflowSearchAttributesEventAttributes {
277
+ workflow_task_completed_event_id: 0,
278
+ search_attributes: Some(SearchAttributes {
279
+ indexed_fields: HashMap::from([("Yo".to_string(), Payload::default())]),
280
+ }),
281
+ };
227
282
  let recorded_history_event = HistoryEvent {
228
283
  event_type: EventType::UpsertWorkflowSearchAttributes as i32,
284
+ attributes: Some(
285
+ history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(
286
+ sa_attribs,
287
+ ),
288
+ ),
229
289
  ..Default::default()
230
290
  };
231
291
  assert!(sm.matches_event(&recorded_history_event));
232
- let cmd_recorded_sm_event = recorded_history_event.try_into().unwrap();
292
+ let cmd_recorded_sm_event = HistEventData {
293
+ event: recorded_history_event,
294
+ replaying: false,
295
+ current_task_is_last_in_history: true,
296
+ }
297
+ .try_into()
298
+ .unwrap();
233
299
 
234
- OnEventWrapper::on_event_mut(&mut sm, cmd_scheduled_sm_event)
235
- .expect("CommandScheduled should transition Created -> CommandIssued");
300
+ OnEventWrapper::on_event_mut(
301
+ &mut sm,
302
+ CommandType::UpsertWorkflowSearchAttributes
303
+ .try_into()
304
+ .unwrap(),
305
+ )
306
+ .expect("CommandScheduled should transition Created -> CommandIssued");
236
307
  assert_eq!(CommandIssued {}.to_string(), sm.state().to_string());
237
308
 
238
- OnEventWrapper::on_event_mut(&mut sm, cmd_recorded_sm_event)
239
- .expect("CommandRecorded should transition CommandIssued -> Done");
309
+ let recorded_res = OnEventWrapper::on_event_mut(&mut sm, cmd_recorded_sm_event);
310
+ recorded_res.expect("CommandRecorded should transition CommandIssued -> Done");
240
311
  assert_eq!(Done {}.to_string(), sm.state().to_string());
241
312
  }
313
+
314
+ #[rstest::rstest]
315
+ #[tokio::test]
316
+ async fn upserting_change_version_directly(
317
+ #[values(true, false)] flag_in_history: bool,
318
+ #[values(true, false)] with_patched_cmd: bool,
319
+ ) {
320
+ let patch_id = "whatever".to_string();
321
+ let mut t = TestHistoryBuilder::default();
322
+ t.add_by_type(EventType::WorkflowExecutionStarted);
323
+ t.add_full_wf_task();
324
+ if flag_in_history {
325
+ t.set_flags_first_wft(
326
+ &[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
327
+ &[],
328
+ );
329
+ }
330
+ if with_patched_cmd {
331
+ t.add_has_change_marker(&patch_id, false);
332
+ }
333
+ t.add_upsert_search_attrs_for_patch(&[patch_id.clone()]);
334
+ t.add_full_wf_task();
335
+ t.add_workflow_execution_completed();
336
+
337
+ let mut mp = MockPollCfg::from_resp_batches(
338
+ "fakeid",
339
+ t,
340
+ [ResponseType::ToTaskNum(1), ResponseType::AllHistory],
341
+ mock_workflow_client(),
342
+ );
343
+ // Ensure the upsert command has an empty map when not using the patched command
344
+ if !with_patched_cmd {
345
+ mp.completion_asserts = Some(Box::new(|wftc| {
346
+ assert_matches!(wftc.commands.get(0).and_then(|c| c.attributes.as_ref()).unwrap(),
347
+ Attributes::UpsertWorkflowSearchAttributesCommandAttributes(attrs)
348
+ if attrs.search_attributes.as_ref().unwrap().indexed_fields.is_empty())
349
+ }));
350
+ }
351
+ let core = mock_worker(build_mock_pollers(mp));
352
+
353
+ let mut ver_upsert = HashMap::new();
354
+ ver_upsert.insert(
355
+ VERSION_SEARCH_ATTR_KEY.to_string(),
356
+ "hi".as_json_payload().unwrap(),
357
+ );
358
+ let act = core.poll_workflow_activation().await.unwrap();
359
+ let mut cmds = if with_patched_cmd {
360
+ vec![SetPatchMarker {
361
+ patch_id,
362
+ deprecated: false,
363
+ }
364
+ .into()]
365
+ } else {
366
+ vec![]
367
+ };
368
+ cmds.push(
369
+ UpsertWorkflowSearchAttributes {
370
+ search_attributes: ver_upsert,
371
+ }
372
+ .into(),
373
+ );
374
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
375
+ act.run_id, cmds,
376
+ ))
377
+ .await
378
+ .unwrap();
379
+ // Now ensure that encountering the upsert in history works fine
380
+ let act = core.poll_workflow_activation().await.unwrap();
381
+ core.complete_execution(&act.run_id).await;
382
+ }
242
383
  }