@temporalio/core-bridge 0.17.2 → 0.18.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 (170) hide show
  1. package/Cargo.lock +339 -226
  2. package/Cargo.toml +7 -3
  3. package/common.js +50 -0
  4. package/index.d.ts +7 -0
  5. package/index.js +12 -0
  6. package/package.json +7 -4
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/{index.node → releases/index.node} +0 -0
  10. package/releases/x86_64-apple-darwin/index.node +0 -0
  11. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  12. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  13. package/scripts/build.js +10 -50
  14. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  15. package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
  16. package/sdk-core/.buildkite/pipeline.yml +2 -0
  17. package/sdk-core/Cargo.toml +1 -88
  18. package/sdk-core/README.md +30 -6
  19. package/sdk-core/bridge-ffi/Cargo.toml +24 -0
  20. package/sdk-core/bridge-ffi/LICENSE.txt +23 -0
  21. package/sdk-core/bridge-ffi/build.rs +25 -0
  22. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +216 -0
  23. package/sdk-core/bridge-ffi/src/lib.rs +829 -0
  24. package/sdk-core/bridge-ffi/src/wrappers.rs +193 -0
  25. package/sdk-core/client/Cargo.toml +32 -0
  26. package/sdk-core/{src/pollers/gateway.rs → client/src/lib.rs} +101 -195
  27. package/sdk-core/client/src/metrics.rs +89 -0
  28. package/sdk-core/client/src/mocks.rs +167 -0
  29. package/sdk-core/{src/pollers → client/src}/retry.rs +172 -14
  30. package/sdk-core/core/Cargo.toml +96 -0
  31. package/sdk-core/{src → core/src}/core_tests/activity_tasks.rs +193 -37
  32. package/sdk-core/{src → core/src}/core_tests/child_workflows.rs +14 -14
  33. package/sdk-core/{src → core/src}/core_tests/determinism.rs +8 -8
  34. package/sdk-core/core/src/core_tests/local_activities.rs +328 -0
  35. package/sdk-core/{src → core/src}/core_tests/mod.rs +6 -9
  36. package/sdk-core/{src → core/src}/core_tests/queries.rs +45 -52
  37. package/sdk-core/{src → core/src}/core_tests/replay_flag.rs +8 -12
  38. package/sdk-core/{src → core/src}/core_tests/workers.rs +120 -33
  39. package/sdk-core/{src → core/src}/core_tests/workflow_cancels.rs +16 -26
  40. package/sdk-core/{src → core/src}/core_tests/workflow_tasks.rs +264 -286
  41. package/sdk-core/core/src/lib.rs +374 -0
  42. package/sdk-core/{src → core/src}/log_export.rs +3 -27
  43. package/sdk-core/core/src/pending_activations.rs +162 -0
  44. package/sdk-core/{src → core/src}/pollers/mod.rs +4 -22
  45. package/sdk-core/{src → core/src}/pollers/poll_buffer.rs +1 -1
  46. package/sdk-core/core/src/protosext/mod.rs +396 -0
  47. package/sdk-core/core/src/replay/mod.rs +210 -0
  48. package/sdk-core/core/src/retry_logic.rs +144 -0
  49. package/sdk-core/{src → core/src}/telemetry/metrics.rs +3 -58
  50. package/sdk-core/{src → core/src}/telemetry/mod.rs +8 -8
  51. package/sdk-core/{src → core/src}/telemetry/prometheus_server.rs +0 -0
  52. package/sdk-core/{src → core/src}/test_help/mod.rs +34 -73
  53. package/sdk-core/{src → core/src}/worker/activities/activity_heartbeat_manager.rs +95 -42
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +973 -0
  55. package/sdk-core/{src → core/src}/worker/activities.rs +52 -33
  56. package/sdk-core/{src → core/src}/worker/dispatcher.rs +8 -6
  57. package/sdk-core/{src → core/src}/worker/mod.rs +305 -195
  58. package/sdk-core/core/src/worker/wft_delivery.rs +81 -0
  59. package/sdk-core/{src → core/src}/workflow/bridge.rs +5 -2
  60. package/sdk-core/{src → core/src}/workflow/driven_workflow.rs +17 -7
  61. package/sdk-core/{src → core/src}/workflow/history_update.rs +33 -7
  62. package/sdk-core/{src → core/src/workflow}/machines/activity_state_machine.rs +26 -26
  63. package/sdk-core/{src → core/src/workflow}/machines/cancel_external_state_machine.rs +8 -11
  64. package/sdk-core/{src → core/src/workflow}/machines/cancel_workflow_state_machine.rs +19 -21
  65. package/sdk-core/{src → core/src/workflow}/machines/child_workflow_state_machine.rs +19 -21
  66. package/sdk-core/{src → core/src/workflow}/machines/complete_workflow_state_machine.rs +3 -5
  67. package/sdk-core/{src → core/src/workflow}/machines/continue_as_new_workflow_state_machine.rs +18 -18
  68. package/sdk-core/{src → core/src/workflow}/machines/fail_workflow_state_machine.rs +5 -6
  69. package/sdk-core/core/src/workflow/machines/local_activity_state_machine.rs +1451 -0
  70. package/sdk-core/{src → core/src/workflow}/machines/mod.rs +54 -107
  71. package/sdk-core/{src → core/src/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
  72. package/sdk-core/{src → core/src/workflow}/machines/patch_state_machine.rs +29 -30
  73. package/sdk-core/{src → core/src/workflow}/machines/side_effect_state_machine.rs +0 -0
  74. package/sdk-core/{src → core/src/workflow}/machines/signal_external_state_machine.rs +17 -19
  75. package/sdk-core/{src → core/src/workflow}/machines/timer_state_machine.rs +20 -21
  76. package/sdk-core/{src → core/src/workflow}/machines/transition_coverage.rs +5 -2
  77. package/sdk-core/{src → core/src/workflow}/machines/upsert_search_attributes_state_machine.rs +0 -0
  78. package/sdk-core/core/src/workflow/machines/workflow_machines/local_acts.rs +96 -0
  79. package/sdk-core/{src → core/src/workflow}/machines/workflow_machines.rs +344 -160
  80. package/sdk-core/{src → core/src/workflow}/machines/workflow_task_state_machine.rs +1 -1
  81. package/sdk-core/{src → core/src}/workflow/mod.rs +200 -39
  82. package/sdk-core/{src → core/src}/workflow/workflow_tasks/cache_manager.rs +0 -0
  83. package/sdk-core/{src → core/src}/workflow/workflow_tasks/concurrency_manager.rs +38 -5
  84. package/sdk-core/{src → core/src}/workflow/workflow_tasks/mod.rs +297 -81
  85. package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
  86. package/sdk-core/{src → core-api/src}/errors.rs +42 -90
  87. package/sdk-core/core-api/src/lib.rs +158 -0
  88. package/sdk-core/{src/worker/config.rs → core-api/src/worker.rs} +18 -23
  89. package/sdk-core/etc/deps.svg +156 -0
  90. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +5 -5
  91. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +3 -5
  92. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -1
  93. package/sdk-core/histories/fail_wf_task.bin +0 -0
  94. package/sdk-core/histories/timer_workflow_history.bin +0 -0
  95. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +44 -13
  96. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +19 -1
  97. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +1 -1
  98. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +9 -0
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +1 -0
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +1 -0
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +13 -0
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +14 -7
  103. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +176 -18
  104. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  105. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +11 -0
  106. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +3 -0
  107. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +156 -7
  108. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +135 -104
  109. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
  110. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +78 -0
  111. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +205 -0
  112. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +61 -0
  113. package/sdk-core/protos/local/{child_workflow.proto → temporal/sdk/core/child_workflow/child_workflow.proto} +1 -1
  114. package/sdk-core/protos/local/{common.proto → temporal/sdk/core/common/common.proto} +5 -3
  115. package/sdk-core/protos/local/{core_interface.proto → temporal/sdk/core/core_interface.proto} +10 -10
  116. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
  117. package/sdk-core/protos/local/{workflow_activation.proto → temporal/sdk/core/workflow_activation/workflow_activation.proto} +35 -11
  118. package/sdk-core/protos/local/{workflow_commands.proto → temporal/sdk/core/workflow_commands/workflow_commands.proto} +55 -4
  119. package/sdk-core/protos/local/{workflow_completion.proto → temporal/sdk/core/workflow_completion/workflow_completion.proto} +3 -3
  120. package/sdk-core/sdk/Cargo.toml +32 -0
  121. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/conversions.rs +0 -0
  122. package/sdk-core/sdk/src/lib.rs +699 -0
  123. package/sdk-core/sdk/src/payload_converter.rs +11 -0
  124. package/sdk-core/sdk/src/workflow_context/options.rs +180 -0
  125. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_context.rs +201 -124
  126. package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_future.rs +63 -30
  127. package/sdk-core/sdk-core-protos/Cargo.toml +10 -0
  128. package/sdk-core/sdk-core-protos/build.rs +28 -6
  129. package/sdk-core/sdk-core-protos/src/constants.rs +7 -0
  130. package/sdk-core/{src/test_help → sdk-core-protos/src}/history_builder.rs +134 -49
  131. package/sdk-core/sdk-core-protos/src/history_info.rs +216 -0
  132. package/sdk-core/sdk-core-protos/src/lib.rs +594 -168
  133. package/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
  134. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
  135. package/sdk-core/test-utils/Cargo.toml +32 -0
  136. package/sdk-core/{src/test_help → test-utils/src}/canned_histories.rs +59 -78
  137. package/sdk-core/test-utils/src/histfetch.rs +28 -0
  138. package/sdk-core/{test_utils → test-utils}/src/lib.rs +131 -68
  139. package/sdk-core/tests/integ_tests/client_tests.rs +1 -1
  140. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -7
  141. package/sdk-core/tests/integ_tests/polling_tests.rs +12 -11
  142. package/sdk-core/tests/integ_tests/queries_tests.rs +82 -78
  143. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +91 -71
  144. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +3 -4
  145. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +2 -4
  146. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -6
  147. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +4 -6
  148. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -4
  149. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +496 -0
  150. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +5 -8
  151. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +125 -0
  152. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +7 -13
  153. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +33 -5
  154. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +12 -16
  155. package/sdk-core/tests/integ_tests/workflow_tests.rs +85 -82
  156. package/sdk-core/tests/load_tests.rs +6 -6
  157. package/sdk-core/tests/main.rs +2 -2
  158. package/src/conversions.rs +24 -21
  159. package/src/errors.rs +8 -0
  160. package/src/lib.rs +323 -211
  161. package/sdk-core/protos/local/activity_result.proto +0 -46
  162. package/sdk-core/protos/local/activity_task.proto +0 -66
  163. package/sdk-core/src/core_tests/retry.rs +0 -147
  164. package/sdk-core/src/lib.rs +0 -403
  165. package/sdk-core/src/machines/local_activity_state_machine.rs +0 -117
  166. package/sdk-core/src/pending_activations.rs +0 -249
  167. package/sdk-core/src/protosext/mod.rs +0 -160
  168. package/sdk-core/src/prototype_rust_sdk.rs +0 -412
  169. package/sdk-core/src/task_token.rs +0 -20
  170. package/sdk-core/src/test_help/history_info.rs +0 -158
@@ -1,6 +1,6 @@
1
1
  #![allow(clippy::enum_variant_names)]
2
2
 
3
- use crate::machines::{
3
+ use super::{
4
4
  workflow_machines::MachineResponse, Cancellable, EventInfo, MachineKind, WFMachinesAdapter,
5
5
  WFMachinesError,
6
6
  };
@@ -1,31 +1,29 @@
1
+ pub(crate) mod workflow_tasks;
2
+
1
3
  mod bridge;
2
4
  mod driven_workflow;
3
5
  mod history_update;
4
- pub(crate) mod workflow_tasks;
6
+ mod machines;
5
7
 
6
8
  pub(crate) use bridge::WorkflowBridge;
7
9
  pub(crate) use driven_workflow::{DrivenWorkflow, WorkflowFetcher};
8
10
  pub(crate) use history_update::{HistoryPaginator, HistoryUpdate};
11
+ pub(crate) use machines::WFMachinesError;
9
12
 
10
13
  use crate::{
11
- machines::{ProtoCommand, WFCommand, WFMachinesError, WorkflowMachines},
12
14
  telemetry::metrics::MetricsContext,
15
+ worker::{LocalActRequest, LocalActivityResolution},
16
+ };
17
+ use machines::WorkflowMachines;
18
+ use std::{result, sync::mpsc::Sender};
19
+ use temporal_sdk_core_protos::{
20
+ coresdk::{workflow_activation::WorkflowActivation, workflow_commands::*},
21
+ temporal::api::command::v1::Command as ProtoCommand,
13
22
  };
14
- use std::sync::mpsc::Sender;
15
- use temporal_sdk_core_protos::coresdk::workflow_activation::WfActivation;
16
23
 
17
24
  pub(crate) const LEGACY_QUERY_ID: &str = "legacy_query";
18
- type Result<T, E = WFMachinesError> = std::result::Result<T, E>;
19
25
 
20
- #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
21
- pub(crate) enum CommandID {
22
- Timer(u32),
23
- Activity(u32),
24
- ChildWorkflowStart(u32),
25
- ChildWorkflowComplete(u32),
26
- SignalExternal(u32),
27
- CancelExternal(u32),
28
- }
26
+ type Result<T, E = WFMachinesError> = std::result::Result<T, E>;
29
27
 
30
28
  /// Manages an instance of a [WorkflowMachines], which is not thread-safe, as well as other data
31
29
  /// associated with that specific workflow run.
@@ -43,6 +41,7 @@ impl WorkflowManager {
43
41
  history: HistoryUpdate,
44
42
  namespace: String,
45
43
  workflow_id: String,
44
+ workflow_type: String,
46
45
  run_id: String,
47
46
  metrics: MetricsContext,
48
47
  ) -> Self {
@@ -50,6 +49,7 @@ impl WorkflowManager {
50
49
  let state_machines = WorkflowMachines::new(
51
50
  namespace,
52
51
  workflow_id,
52
+ workflow_type,
53
53
  run_id,
54
54
  history,
55
55
  Box::new(wfb).into(),
@@ -76,6 +76,11 @@ pub struct OutgoingServerCommands {
76
76
  pub replaying: bool,
77
77
  }
78
78
 
79
+ #[derive(Debug)]
80
+ pub(crate) enum LocalResolution {
81
+ LocalActivity(LocalActivityResolution),
82
+ }
83
+
79
84
  impl WorkflowManager {
80
85
  /// Given history that was just obtained from the server, pipe it into this workflow's machines.
81
86
  ///
@@ -84,17 +89,23 @@ impl WorkflowManager {
84
89
  pub async fn feed_history_from_server(
85
90
  &mut self,
86
91
  update: HistoryUpdate,
87
- ) -> Result<WfActivation> {
92
+ ) -> Result<WorkflowActivation> {
88
93
  self.machines.new_history_from_server(update).await?;
89
94
  self.get_next_activation().await
90
95
  }
91
96
 
97
+ /// Let this workflow know that something we've been waiting locally on has resolved, like a
98
+ /// local activity or side effect
99
+ pub fn notify_of_local_result(&mut self, resolved: LocalResolution) -> Result<()> {
100
+ self.machines.local_resolution(resolved)
101
+ }
102
+
92
103
  /// Fetch the next workflow activation for this workflow if one is required. Doing so will apply
93
104
  /// the next unapplied workflow task if such a sequence exists in history we already know about.
94
105
  ///
95
106
  /// Callers may also need to call [get_server_commands] after this to issue any pending commands
96
107
  /// to the server.
97
- pub async fn get_next_activation(&mut self) -> Result<WfActivation> {
108
+ pub async fn get_next_activation(&mut self) -> Result<WorkflowActivation> {
98
109
  // First check if there are already some pending jobs, which can be a result of replay.
99
110
  let activation = self.machines.get_wf_activation();
100
111
  if !activation.jobs.is_empty() {
@@ -105,15 +116,43 @@ impl WorkflowManager {
105
116
  Ok(self.machines.get_wf_activation())
106
117
  }
107
118
 
119
+ /// If there are no pending jobs for the workflow, apply the next workflow task and check
120
+ /// again if there are any jobs. Importantly, does not *drain* jobs.
121
+ ///
122
+ /// Returns true if there are jobs (before or after applying the next WFT).
123
+ pub async fn apply_next_task_if_ready(&mut self) -> Result<bool> {
124
+ if self.machines.has_pending_jobs() {
125
+ return Ok(true);
126
+ }
127
+ loop {
128
+ let consumed_events = self.machines.apply_next_wft_from_history().await?;
129
+
130
+ if consumed_events == 0 || !self.machines.replaying || self.machines.has_pending_jobs()
131
+ {
132
+ // Keep applying tasks while there are events, we are still replaying, and there are
133
+ // no jobs
134
+ break;
135
+ }
136
+ }
137
+ Ok(self.machines.has_pending_jobs())
138
+ }
139
+
108
140
  /// Typically called after [get_next_activation], use this to retrieve commands to be sent to
109
- /// the server which been generated by the machines since it was last called.
110
- pub fn get_server_commands(&self) -> OutgoingServerCommands {
141
+ /// the server which have been generated by the machines. Does *not* drain those commands.
142
+ /// See [WorkflowMachines::get_commands].
143
+ pub fn get_server_commands(&mut self) -> OutgoingServerCommands {
111
144
  OutgoingServerCommands {
112
145
  commands: self.machines.get_commands(),
113
146
  replaying: self.machines.replaying,
114
147
  }
115
148
  }
116
149
 
150
+ /// Remove and return all queued local activities. Once this is called, they need to be
151
+ /// dispatched for execution.
152
+ pub fn drain_queued_local_activities(&mut self) -> Vec<LocalActRequest> {
153
+ self.machines.drain_queued_local_activities()
154
+ }
155
+
117
156
  /// Feed the workflow machines new commands issued by the executing workflow code, and iterate
118
157
  /// the machines.
119
158
  pub async fn push_commands(&mut self, cmds: Vec<WFCommand>) -> Result<()> {
@@ -146,20 +185,105 @@ pub(crate) enum WorkflowCachingPolicy {
146
185
  AfterEveryReply,
147
186
  }
148
187
 
188
+ #[derive(thiserror::Error, Debug, derive_more::From)]
189
+ #[error("Lang provided workflow command with empty variant")]
190
+ pub struct EmptyWorkflowCommandErr;
191
+
192
+ /// [DrivenWorkflow]s respond with these when called, to indicate what they want to do next.
193
+ /// EX: Create a new timer, complete the workflow, etc.
194
+ #[derive(Debug, derive_more::From, derive_more::Display)]
195
+ #[allow(clippy::large_enum_variant)]
196
+ pub enum WFCommand {
197
+ /// Returned when we need to wait for the lang sdk to send us something
198
+ NoCommandsFromLang,
199
+ AddActivity(ScheduleActivity),
200
+ AddLocalActivity(ScheduleLocalActivity),
201
+ RequestCancelActivity(RequestCancelActivity),
202
+ RequestCancelLocalActivity(RequestCancelLocalActivity),
203
+ AddTimer(StartTimer),
204
+ CancelTimer(CancelTimer),
205
+ CompleteWorkflow(CompleteWorkflowExecution),
206
+ FailWorkflow(FailWorkflowExecution),
207
+ QueryResponse(QueryResult),
208
+ ContinueAsNew(ContinueAsNewWorkflowExecution),
209
+ CancelWorkflow(CancelWorkflowExecution),
210
+ SetPatchMarker(SetPatchMarker),
211
+ AddChildWorkflow(StartChildWorkflowExecution),
212
+ CancelUnstartedChild(CancelUnstartedChildWorkflowExecution),
213
+ RequestCancelExternalWorkflow(RequestCancelExternalWorkflowExecution),
214
+ SignalExternalWorkflow(SignalExternalWorkflowExecution),
215
+ CancelSignalWorkflow(CancelSignalWorkflow),
216
+ }
217
+
218
+ impl TryFrom<WorkflowCommand> for WFCommand {
219
+ type Error = EmptyWorkflowCommandErr;
220
+
221
+ fn try_from(c: WorkflowCommand) -> result::Result<Self, Self::Error> {
222
+ match c.variant.ok_or(EmptyWorkflowCommandErr)? {
223
+ workflow_command::Variant::StartTimer(s) => Ok(Self::AddTimer(s)),
224
+ workflow_command::Variant::CancelTimer(s) => Ok(Self::CancelTimer(s)),
225
+ workflow_command::Variant::ScheduleActivity(s) => Ok(Self::AddActivity(s)),
226
+ workflow_command::Variant::RequestCancelActivity(s) => {
227
+ Ok(Self::RequestCancelActivity(s))
228
+ }
229
+ workflow_command::Variant::CompleteWorkflowExecution(c) => {
230
+ Ok(Self::CompleteWorkflow(c))
231
+ }
232
+ workflow_command::Variant::FailWorkflowExecution(s) => Ok(Self::FailWorkflow(s)),
233
+ workflow_command::Variant::RespondToQuery(s) => Ok(Self::QueryResponse(s)),
234
+ workflow_command::Variant::ContinueAsNewWorkflowExecution(s) => {
235
+ Ok(Self::ContinueAsNew(s))
236
+ }
237
+ workflow_command::Variant::CancelWorkflowExecution(s) => Ok(Self::CancelWorkflow(s)),
238
+ workflow_command::Variant::SetPatchMarker(s) => Ok(Self::SetPatchMarker(s)),
239
+ workflow_command::Variant::StartChildWorkflowExecution(s) => {
240
+ Ok(Self::AddChildWorkflow(s))
241
+ }
242
+ workflow_command::Variant::RequestCancelExternalWorkflowExecution(s) => {
243
+ Ok(Self::RequestCancelExternalWorkflow(s))
244
+ }
245
+ workflow_command::Variant::SignalExternalWorkflowExecution(s) => {
246
+ Ok(Self::SignalExternalWorkflow(s))
247
+ }
248
+ workflow_command::Variant::CancelSignalWorkflow(s) => Ok(Self::CancelSignalWorkflow(s)),
249
+ workflow_command::Variant::CancelUnstartedChildWorkflowExecution(s) => {
250
+ Ok(Self::CancelUnstartedChild(s))
251
+ }
252
+ workflow_command::Variant::ScheduleLocalActivity(s) => Ok(Self::AddLocalActivity(s)),
253
+ workflow_command::Variant::RequestCancelLocalActivity(s) => {
254
+ Ok(Self::RequestCancelLocalActivity(s))
255
+ }
256
+ }
257
+ }
258
+ }
259
+
260
+ #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
261
+ enum CommandID {
262
+ Timer(u32),
263
+ Activity(u32),
264
+ LocalActivity(u32),
265
+ ChildWorkflowStart(u32),
266
+ SignalExternal(u32),
267
+ CancelExternal(u32),
268
+ }
269
+
149
270
  #[cfg(test)]
150
271
  pub mod managed_wf {
151
272
  use super::*;
152
273
  use crate::{
153
- machines::WFCommand,
154
- prototype_rust_sdk::{WorkflowFunction, WorkflowResult},
155
- test_help::{TestHistoryBuilder, TEST_Q},
156
- workflow::WorkflowFetcher,
274
+ replay::TestHistoryBuilder,
275
+ test_help::TEST_Q,
276
+ workflow::{history_update::TestHBExt, WFCommand, WorkflowFetcher},
157
277
  };
158
- use std::convert::TryInto;
278
+ use std::{convert::TryInto, time::Duration};
279
+ use temporal_sdk::{WorkflowFunction, WorkflowResult};
159
280
  use temporal_sdk_core_protos::coresdk::{
281
+ activity_result::ActivityExecutionResult,
160
282
  common::Payload,
161
- workflow_activation::create_evict_activation,
162
- workflow_completion::{wf_activation_completion::Status, WfActivationCompletion},
283
+ workflow_activation::{create_evict_activation, remove_from_cache::EvictionReason},
284
+ workflow_completion::{
285
+ workflow_activation_completion::Status, WorkflowActivationCompletion,
286
+ },
163
287
  };
164
288
  use tokio::{
165
289
  sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
@@ -167,13 +291,14 @@ pub mod managed_wf {
167
291
  };
168
292
 
169
293
  pub(crate) struct WFFutureDriver {
170
- completions_rx: UnboundedReceiver<WfActivationCompletion>,
294
+ completions_rx: UnboundedReceiver<WorkflowActivationCompletion>,
171
295
  }
172
296
 
173
297
  #[async_trait::async_trait]
174
298
  impl WorkflowFetcher for WFFutureDriver {
175
299
  async fn fetch_workflow_iteration_output(&mut self) -> Vec<WFCommand> {
176
300
  if let Some(completion) = self.completions_rx.recv().await {
301
+ debug!("Managed wf completion: {}", completion);
177
302
  completion
178
303
  .status
179
304
  .map(|s| match s {
@@ -195,7 +320,7 @@ pub mod managed_wf {
195
320
  #[must_use]
196
321
  pub struct ManagedWFFunc {
197
322
  mgr: WorkflowManager,
198
- activation_tx: UnboundedSender<WfActivation>,
323
+ activation_tx: UnboundedSender<WorkflowActivation>,
199
324
  future_handle: Option<JoinHandle<WorkflowResult<()>>>,
200
325
  was_shutdown: bool,
201
326
  }
@@ -222,6 +347,7 @@ pub mod managed_wf {
222
347
  let state_machines = WorkflowMachines::new(
223
348
  "test_namespace".to_string(),
224
349
  "wfid".to_string(),
350
+ "wftype".to_string(),
225
351
  "runid".to_string(),
226
352
  hist,
227
353
  Box::new(driver).into(),
@@ -236,33 +362,62 @@ pub mod managed_wf {
236
362
  }
237
363
  }
238
364
 
239
- pub(crate) async fn get_next_activation(&mut self) -> Result<WfActivation> {
365
+ #[instrument(level = "debug", skip(self))]
366
+ pub(crate) async fn get_next_activation(&mut self) -> Result<WorkflowActivation> {
240
367
  let res = self.mgr.get_next_activation().await?;
241
368
  debug!("Managed wf next activation: {}", &res);
242
- if res.jobs.is_empty() {
243
- // Nothing to do here
244
- return Ok(res);
245
- }
246
- self.push_activation_to_wf(res.clone()).await?;
369
+ self.push_activation_to_wf(&res).await?;
247
370
  Ok(res)
248
371
  }
249
372
 
250
373
  /// Return outgoing server commands as of the last iteration
251
- pub(crate) async fn get_server_commands(&mut self) -> OutgoingServerCommands {
374
+ pub(crate) fn get_server_commands(&mut self) -> OutgoingServerCommands {
252
375
  self.mgr.get_server_commands()
253
376
  }
254
377
 
378
+ pub(crate) fn drain_queued_local_activities(&mut self) -> Vec<LocalActRequest> {
379
+ self.mgr.drain_queued_local_activities()
380
+ }
381
+
255
382
  /// Feed new history, as if received a new poll result. Returns new activation
256
- pub(crate) async fn new_history(&mut self, update: HistoryUpdate) -> Result<WfActivation> {
383
+ #[instrument(level = "debug", skip(self, update))]
384
+ pub(crate) async fn new_history(
385
+ &mut self,
386
+ update: HistoryUpdate,
387
+ ) -> Result<WorkflowActivation> {
257
388
  let res = self.mgr.feed_history_from_server(update).await?;
258
- self.push_activation_to_wf(res.clone()).await?;
389
+ self.push_activation_to_wf(&res).await?;
259
390
  Ok(res)
260
391
  }
261
392
 
393
+ /// Say a local activity completed (they always take 1 second in these tests)
394
+ pub(crate) fn complete_local_activity(
395
+ &mut self,
396
+ seq_num: u32,
397
+ result: ActivityExecutionResult,
398
+ ) -> Result<()> {
399
+ self.mgr
400
+ .notify_of_local_result(LocalResolution::LocalActivity(LocalActivityResolution {
401
+ seq: seq_num,
402
+ // We accept normal execution results and do this conversion because there
403
+ // are more helpers for constructing them.
404
+ result: result
405
+ .status
406
+ .expect("LA result must have a status")
407
+ .try_into()
408
+ .expect("LA execution result must be a valid LA result"),
409
+ runtime: Duration::from_secs(1),
410
+ attempt: 1,
411
+ backoff: None,
412
+ // Tests at this level don't use the LA dispatcher, so this is irrelevant
413
+ original_schedule_time: None,
414
+ }))
415
+ }
416
+
262
417
  /// During testing it can be useful to run through all activations to simulate replay
263
418
  /// easily. Returns the last produced activation with jobs in it, or an activation with no
264
419
  /// jobs if the first call had no jobs.
265
- pub(crate) async fn process_all_activations(&mut self) -> Result<WfActivation> {
420
+ pub(crate) async fn process_all_activations(&mut self) -> Result<WorkflowActivation> {
266
421
  let mut last_act = self.get_next_activation().await?;
267
422
  let mut next_act = self.get_next_activation().await?;
268
423
  while !next_act.jobs.is_empty() {
@@ -278,13 +433,19 @@ pub mod managed_wf {
278
433
  let _ = self.activation_tx.send(create_evict_activation(
279
434
  "not actually important".to_string(),
280
435
  "force shutdown".to_string(),
436
+ EvictionReason::Unspecified,
281
437
  ));
282
438
  self.future_handle.take().unwrap().await.unwrap()
283
439
  }
284
440
 
285
- async fn push_activation_to_wf(&mut self, res: WfActivation) -> Result<()> {
441
+ #[instrument(level = "debug", skip(self, res))]
442
+ async fn push_activation_to_wf(&mut self, res: &WorkflowActivation) -> Result<()> {
443
+ if res.jobs.is_empty() {
444
+ // Nothing to do here
445
+ return Ok(());
446
+ }
286
447
  self.activation_tx
287
- .send(res)
448
+ .send(res.clone())
288
449
  .expect("Workflow should not be dropped if we are still sending activations");
289
450
  self.mgr.machines.iterate_machines().await?;
290
451
  Ok(())
@@ -1,9 +1,8 @@
1
1
  use crate::{
2
- errors::WorkflowMissingError,
3
2
  protosext::ValidPollWFTQResponse,
4
3
  telemetry::metrics::{workflow_type, MetricsContext},
5
4
  workflow::{
6
- workflow_tasks::{OutstandingActivation, OutstandingTask},
5
+ workflow_tasks::{OutstandingActivation, OutstandingTask, WorkflowMissingError},
7
6
  HistoryUpdate, Result, WFMachinesError, WorkflowManager,
8
7
  },
9
8
  };
@@ -14,7 +13,7 @@ use std::{
14
13
  fmt::Debug,
15
14
  ops::{Deref, DerefMut},
16
15
  };
17
- use temporal_sdk_core_protos::coresdk::workflow_activation::WfActivation;
16
+ use temporal_sdk_core_protos::coresdk::workflow_activation::WorkflowActivation;
18
17
 
19
18
  /// Provides a thread-safe way to access workflow machines for specific workflow runs
20
19
  pub(crate) struct WorkflowConcurrencyManager {
@@ -151,7 +150,23 @@ impl WorkflowConcurrencyManager {
151
150
  }
152
151
 
153
152
  /// Indicate it's finished and remove any outstanding workflow task associated with the run
154
- pub fn complete_wft(&self, run_id: &str) -> Option<OutstandingTask> {
153
+ pub fn complete_wft(
154
+ &self,
155
+ run_id: &str,
156
+ send_wft_complete_to_srv: bool,
157
+ ) -> Option<OutstandingTask> {
158
+ // If the WFT completion wasn't sent to the server, but we did see the final event, we still
159
+ // want to clear the workflow task. This can really only happen in replay testing, where we
160
+ // will generate poll responses with complete history but no attached query, and such a WFT
161
+ // would never really exist. The server wouldn't send a workflow task with nothing to do,
162
+ // but they are very useful for testing complete replay.
163
+ let saw_final = self
164
+ .access_sync(run_id, |wfm| wfm.machines.have_seen_terminal_event)
165
+ .unwrap_or_default();
166
+ if !saw_final && !send_wft_complete_to_srv {
167
+ return None;
168
+ }
169
+
155
170
  let retme = if let Ok(ot) = self.get_task_mut(run_id).as_deref_mut() {
156
171
  (*ot).take()
157
172
  } else {
@@ -201,7 +216,7 @@ impl WorkflowConcurrencyManager {
201
216
  namespace: &str,
202
217
  wf_type: &str,
203
218
  parent_metrics: &MetricsContext,
204
- ) -> Result<WfActivation> {
219
+ ) -> Result<WorkflowActivation> {
205
220
  let span = debug_span!("create_or_update machines", %run_id);
206
221
 
207
222
  if self.runs.read().contains_key(run_id) {
@@ -224,6 +239,7 @@ impl WorkflowConcurrencyManager {
224
239
  history,
225
240
  namespace.to_owned(),
226
241
  workflow_id.to_owned(),
242
+ wf_type.to_owned(),
227
243
  run_id.to_owned(),
228
244
  metrics.clone(),
229
245
  );
@@ -263,6 +279,23 @@ impl WorkflowConcurrencyManager {
263
279
  res
264
280
  }
265
281
 
282
+ pub fn access_sync<F, Fout>(
283
+ &self,
284
+ run_id: &str,
285
+ mutator: F,
286
+ ) -> Result<Fout, WorkflowMissingError>
287
+ where
288
+ F: for<'a> FnOnce(&'a mut WorkflowManager) -> Fout,
289
+ Fout: Send + Debug,
290
+ {
291
+ let readlock = self.runs.read();
292
+ let m = readlock.get(run_id).ok_or_else(|| WorkflowMissingError {
293
+ run_id: run_id.to_string(),
294
+ })?;
295
+ let mut wfm_mutex = m.wfm.lock();
296
+ Ok(mutator(&mut wfm_mutex))
297
+ }
298
+
266
299
  /// Remove the workflow with the provided run id from management
267
300
  pub fn evict(&self, run_id: &str) -> Option<ValidPollWFTQResponse> {
268
301
  let val = self.runs.write().remove(run_id);