@temporalio/core-bridge 0.23.0 → 1.0.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 (135) hide show
  1. package/Cargo.lock +118 -15
  2. package/Cargo.toml +2 -1
  3. package/LICENSE.md +1 -1
  4. package/README.md +1 -1
  5. package/index.d.ts +47 -18
  6. package/package.json +7 -7
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/releases/x86_64-apple-darwin/index.node +0 -0
  10. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  11. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  12. package/sdk-core/.buildkite/docker/docker-compose.yaml +4 -2
  13. package/sdk-core/ARCHITECTURE.md +9 -7
  14. package/sdk-core/README.md +5 -1
  15. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -3
  17. package/sdk-core/client/src/lib.rs +26 -8
  18. package/sdk-core/client/src/raw.rs +166 -54
  19. package/sdk-core/client/src/retry.rs +9 -4
  20. package/sdk-core/client/src/workflow_handle/mod.rs +4 -2
  21. package/sdk-core/core/Cargo.toml +2 -0
  22. package/sdk-core/core/src/abstractions.rs +137 -16
  23. package/sdk-core/core/src/core_tests/activity_tasks.rs +258 -63
  24. package/sdk-core/core/src/core_tests/child_workflows.rs +1 -2
  25. package/sdk-core/core/src/core_tests/determinism.rs +2 -2
  26. package/sdk-core/core/src/core_tests/local_activities.rs +8 -7
  27. package/sdk-core/core/src/core_tests/queries.rs +146 -60
  28. package/sdk-core/core/src/core_tests/replay_flag.rs +1 -1
  29. package/sdk-core/core/src/core_tests/workers.rs +39 -23
  30. package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
  31. package/sdk-core/core/src/core_tests/workflow_tasks.rs +387 -280
  32. package/sdk-core/core/src/lib.rs +6 -4
  33. package/sdk-core/core/src/pollers/poll_buffer.rs +16 -10
  34. package/sdk-core/core/src/protosext/mod.rs +6 -6
  35. package/sdk-core/core/src/retry_logic.rs +1 -1
  36. package/sdk-core/core/src/telemetry/metrics.rs +21 -7
  37. package/sdk-core/core/src/telemetry/mod.rs +18 -4
  38. package/sdk-core/core/src/test_help/mod.rs +341 -109
  39. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +18 -9
  40. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -16
  41. package/sdk-core/core/src/worker/activities.rs +156 -29
  42. package/sdk-core/core/src/worker/client.rs +1 -0
  43. package/sdk-core/core/src/worker/mod.rs +132 -659
  44. package/sdk-core/core/src/{workflow → worker/workflow}/bridge.rs +1 -1
  45. package/sdk-core/core/src/{workflow → worker/workflow}/driven_workflow.rs +1 -1
  46. package/sdk-core/core/src/{workflow → worker/workflow}/history_update.rs +16 -2
  47. package/sdk-core/core/src/{workflow → worker/workflow}/machines/activity_state_machine.rs +39 -4
  48. package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_external_state_machine.rs +5 -2
  49. package/sdk-core/core/src/{workflow → worker/workflow}/machines/cancel_workflow_state_machine.rs +1 -1
  50. package/sdk-core/core/src/{workflow → worker/workflow}/machines/child_workflow_state_machine.rs +2 -4
  51. package/sdk-core/core/src/{workflow → worker/workflow}/machines/complete_workflow_state_machine.rs +0 -0
  52. package/sdk-core/core/src/{workflow → worker/workflow}/machines/continue_as_new_workflow_state_machine.rs +1 -1
  53. package/sdk-core/core/src/{workflow → worker/workflow}/machines/fail_workflow_state_machine.rs +0 -0
  54. package/sdk-core/core/src/{workflow → worker/workflow}/machines/local_activity_state_machine.rs +2 -5
  55. package/sdk-core/core/src/{workflow → worker/workflow}/machines/mod.rs +1 -1
  56. package/sdk-core/core/src/{workflow → worker/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
  57. package/sdk-core/core/src/{workflow → worker/workflow}/machines/patch_state_machine.rs +1 -1
  58. package/sdk-core/core/src/{workflow → worker/workflow}/machines/side_effect_state_machine.rs +0 -0
  59. package/sdk-core/core/src/{workflow → worker/workflow}/machines/signal_external_state_machine.rs +4 -2
  60. package/sdk-core/core/src/{workflow → worker/workflow}/machines/timer_state_machine.rs +1 -2
  61. package/sdk-core/core/src/{workflow → worker/workflow}/machines/transition_coverage.rs +1 -1
  62. package/sdk-core/core/src/{workflow → worker/workflow}/machines/upsert_search_attributes_state_machine.rs +5 -7
  63. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines/local_acts.rs +2 -2
  64. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_machines.rs +40 -16
  65. package/sdk-core/core/src/{workflow → worker/workflow}/machines/workflow_task_state_machine.rs +0 -0
  66. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
  67. package/sdk-core/core/src/worker/workflow/managed_run.rs +627 -0
  68. package/sdk-core/core/src/worker/workflow/mod.rs +1115 -0
  69. package/sdk-core/core/src/worker/workflow/run_cache.rs +143 -0
  70. package/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
  71. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +936 -0
  72. package/sdk-core/core-api/src/errors.rs +3 -10
  73. package/sdk-core/core-api/src/lib.rs +2 -1
  74. package/sdk-core/core-api/src/worker.rs +26 -2
  75. package/sdk-core/etc/dynamic-config.yaml +2 -0
  76. package/sdk-core/integ-with-otel.sh +1 -1
  77. package/sdk-core/protos/api_upstream/Makefile +4 -4
  78. package/sdk-core/protos/api_upstream/api-linter.yaml +2 -0
  79. package/sdk-core/protos/api_upstream/buf.yaml +8 -9
  80. package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
  81. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -1
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
  83. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
  84. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +3 -1
  85. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
  86. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +3 -0
  87. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +32 -4
  88. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +69 -19
  89. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +13 -0
  90. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +163 -0
  91. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +97 -0
  92. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
  93. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +25 -0
  94. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +180 -3
  95. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +53 -3
  96. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +2 -2
  97. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +6 -5
  98. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -1
  99. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +2 -1
  100. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +0 -64
  101. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -1
  102. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +11 -8
  103. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +30 -25
  104. package/sdk-core/sdk/src/activity_context.rs +12 -5
  105. package/sdk-core/sdk/src/app_data.rs +37 -0
  106. package/sdk-core/sdk/src/lib.rs +76 -43
  107. package/sdk-core/sdk/src/workflow_context/options.rs +8 -6
  108. package/sdk-core/sdk/src/workflow_context.rs +14 -19
  109. package/sdk-core/sdk/src/workflow_future.rs +11 -6
  110. package/sdk-core/sdk-core-protos/src/history_builder.rs +19 -5
  111. package/sdk-core/sdk-core-protos/src/history_info.rs +11 -6
  112. package/sdk-core/sdk-core-protos/src/lib.rs +74 -176
  113. package/sdk-core/test-utils/src/lib.rs +85 -72
  114. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -9
  115. package/sdk-core/tests/integ_tests/polling_tests.rs +12 -0
  116. package/sdk-core/tests/integ_tests/queries_tests.rs +39 -22
  117. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +49 -4
  118. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  120. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +74 -13
  121. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +19 -0
  122. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
  123. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -3
  124. package/sdk-core/tests/integ_tests/workflow_tests.rs +10 -23
  125. package/sdk-core/tests/load_tests.rs +8 -3
  126. package/sdk-core/tests/main.rs +2 -1
  127. package/src/conversions.rs +47 -39
  128. package/src/errors.rs +10 -21
  129. package/src/lib.rs +342 -325
  130. package/sdk-core/core/src/pending_activations.rs +0 -173
  131. package/sdk-core/core/src/worker/wft_delivery.rs +0 -81
  132. package/sdk-core/core/src/workflow/mod.rs +0 -478
  133. package/sdk-core/core/src/workflow/workflow_tasks/cache_manager.rs +0 -194
  134. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +0 -418
  135. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +0 -989
@@ -1,418 +0,0 @@
1
- use crate::{
2
- protosext::ValidPollWFTQResponse,
3
- telemetry::metrics::{workflow_type, MetricsContext},
4
- workflow::{
5
- workflow_tasks::{OutstandingActivation, OutstandingTask, WorkflowMissingError},
6
- HistoryUpdate, Result, WFMachinesError, WorkflowManager,
7
- },
8
- };
9
- use futures::future::{BoxFuture, FutureExt};
10
- use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
11
- use std::{
12
- collections::HashMap,
13
- fmt::Debug,
14
- ops::{Deref, DerefMut},
15
- sync::Arc,
16
- };
17
- use temporal_sdk_core_protos::coresdk::workflow_activation::WorkflowActivation;
18
-
19
- /// Provides a thread-safe way to access workflow machines for specific workflow runs
20
- pub(crate) struct WorkflowConcurrencyManager {
21
- /// Maps run id -> data about and machines for that run
22
- runs: RwLock<HashMap<String, ManagedRun>>,
23
- }
24
-
25
- struct ManagedRun {
26
- wfm: Arc<Mutex<WorkflowManager>>,
27
- wft: Option<OutstandingTask>,
28
- activation: Option<OutstandingActivation>,
29
- metrics: MetricsContext,
30
- /// If set, it indicates there is a buffered poll response from the server that applies to this
31
- /// run. This can happen when lang takes too long to complete a task and the task times out, for
32
- /// example. Upon next completion, the buffered response will be removed and can be made ready
33
- /// to be returned from polling
34
- buffered_resp: Option<ValidPollWFTQResponse>,
35
- }
36
-
37
- impl ManagedRun {
38
- fn new(wfm: WorkflowManager, metrics: MetricsContext) -> Self {
39
- Self {
40
- wfm: Arc::new(Mutex::new(wfm)),
41
- wft: None,
42
- activation: None,
43
- metrics,
44
- buffered_resp: None,
45
- }
46
- }
47
- }
48
-
49
- impl WorkflowConcurrencyManager {
50
- pub fn new() -> Self {
51
- Self {
52
- runs: Default::default(),
53
- }
54
- }
55
-
56
- /// Allows access to outstanding task for a run. Returns `None` if there is no knowledge of
57
- /// the run at all, or if the run exists but there is no outstanding workflow task.
58
- pub(crate) fn get_task(
59
- &self,
60
- run_id: &str,
61
- ) -> Option<impl Deref<Target = OutstandingTask> + '_> {
62
- let readlock = self.runs.read();
63
- if let Some(run) = readlock.get(run_id) {
64
- if run.wft.is_some() {
65
- Some(RwLockReadGuard::map(readlock, |hm| {
66
- // Unwraps are safe because we hold the lock and just ensured run is in the map
67
- hm.get(run_id).unwrap().wft.as_ref().unwrap()
68
- }))
69
- } else {
70
- None
71
- }
72
- } else {
73
- None
74
- }
75
- }
76
-
77
- /// Allows access to outstanding activation slot for a run. Returns `None` if there is no
78
- /// knowledge of the run at all, or if the run exists but there is no outstanding activation.
79
- pub(crate) fn get_activation(&self, run_id: &str) -> Option<OutstandingActivation> {
80
- let readlock = self.runs.read();
81
- if readlock.contains_key(run_id) {
82
- readlock.get(run_id).unwrap().activation
83
- } else {
84
- None
85
- }
86
- }
87
-
88
- /// Allows mutable access to outstanding workflow task slot for a run
89
- pub(crate) fn get_task_mut(
90
- &self,
91
- run_id: &str,
92
- ) -> Result<impl DerefMut<Target = Option<OutstandingTask>> + '_, WorkflowMissingError> {
93
- let writelock = self.runs.write();
94
- if writelock.contains_key(run_id) {
95
- Ok(RwLockWriteGuard::map(writelock, |hm| {
96
- // Unwrap is safe because we hold the lock and just ensured run is in the map
97
- &mut hm.get_mut(run_id).unwrap().wft
98
- }))
99
- } else {
100
- Err(WorkflowMissingError {
101
- run_id: run_id.to_owned(),
102
- })
103
- }
104
- }
105
-
106
- /// Fetch metrics context for a run
107
- pub(crate) fn run_metrics(
108
- &self,
109
- run_id: &str,
110
- ) -> Option<impl Deref<Target = MetricsContext> + '_> {
111
- let readlock = self.runs.read();
112
- if readlock.get(run_id).is_some() {
113
- Some(RwLockReadGuard::map(readlock, |hm| {
114
- // Unwraps are safe because we hold the lock and just ensured run is in the map
115
- &hm.get(run_id).unwrap().metrics
116
- }))
117
- } else {
118
- None
119
- }
120
- }
121
-
122
- /// Stores some work if there is any outstanding WFT or activation for the run. If there was
123
- /// not, returns the work back out inside the option.
124
- pub fn buffer_resp_if_outstanding_work(
125
- &self,
126
- work: ValidPollWFTQResponse,
127
- ) -> Option<ValidPollWFTQResponse> {
128
- let mut writelock = self.runs.write();
129
- let run_id = &work.workflow_execution.run_id;
130
- if let Some(mut run) = writelock.get_mut(run_id) {
131
- if run.wft.is_some() || run.activation.is_some() {
132
- debug!(run_id = %run_id, "Got new WFT for a run with outstanding work");
133
- run.buffered_resp = Some(work);
134
- None
135
- } else {
136
- Some(work)
137
- }
138
- } else {
139
- Some(work)
140
- }
141
- }
142
-
143
- pub fn insert_wft(
144
- &self,
145
- run_id: &str,
146
- task: OutstandingTask,
147
- ) -> Result<(), WorkflowMissingError> {
148
- let mut dereffer = self.get_task_mut(run_id)?;
149
- *dereffer = Some(task);
150
- Ok(())
151
- }
152
-
153
- /// Indicate it's finished and remove any outstanding workflow task associated with the run
154
- pub fn complete_wft(
155
- &self,
156
- run_id: &str,
157
- sent_wft_complete_to_srv: bool,
158
- ) -> Option<OutstandingTask> {
159
- // If the WFT completion wasn't sent to the server, but we did see the final event, we still
160
- // want to clear the workflow task. This can really only happen in replay testing, where we
161
- // will generate poll responses with complete history but no attached query, and such a WFT
162
- // would never really exist. The server wouldn't send a workflow task with nothing to do,
163
- // but they are very useful for testing complete replay.
164
- let saw_final = self
165
- .access_sync(run_id, |wfm| wfm.machines.have_seen_terminal_event)
166
- .unwrap_or_default();
167
- if !saw_final && !sent_wft_complete_to_srv {
168
- return None;
169
- }
170
-
171
- let retme = if let Ok(ot) = self.get_task_mut(run_id).as_deref_mut() {
172
- (*ot).take()
173
- } else {
174
- None
175
- };
176
- if let Some(ot) = &retme {
177
- if let Some(m) = self.run_metrics(run_id) {
178
- m.wf_task_latency(ot.start_time.elapsed());
179
- }
180
- }
181
- retme
182
- }
183
-
184
- pub fn insert_activation(
185
- &self,
186
- run_id: &str,
187
- activation: OutstandingActivation,
188
- ) -> Result<Option<OutstandingActivation>, WorkflowMissingError> {
189
- let mut writelock = self.runs.write();
190
- let machine_ref = writelock.get_mut(run_id);
191
- if let Some(run) = machine_ref {
192
- Ok(run.activation.replace(activation))
193
- } else {
194
- Err(WorkflowMissingError {
195
- run_id: run_id.to_owned(),
196
- })
197
- }
198
- }
199
-
200
- pub fn delete_activation(&self, run_id: &str) -> Option<OutstandingActivation> {
201
- let mut writelock = self.runs.write();
202
- let machine_ref = writelock.get_mut(run_id);
203
- machine_ref.and_then(|run| run.activation.take())
204
- }
205
-
206
- pub fn exists(&self, run_id: &str) -> bool {
207
- self.runs.read().get(run_id).is_some()
208
- }
209
-
210
- /// Create or update some workflow's machines. Borrowed arguments are cloned in the case of a
211
- /// new workflow instance.
212
- pub async fn create_or_update(
213
- &self,
214
- run_id: &str,
215
- history: HistoryUpdate,
216
- workflow_id: &str,
217
- namespace: &str,
218
- wf_type: &str,
219
- parent_metrics: &MetricsContext,
220
- ) -> Result<WorkflowActivation> {
221
- let span = debug_span!("create_or_update machines", %run_id);
222
-
223
- if self.runs.read().contains_key(run_id) {
224
- let activation = self
225
- .access(run_id, move |wfm: &mut WorkflowManager| {
226
- async move {
227
- let _enter = span.enter();
228
- wfm.machines.metrics.sticky_cache_hit();
229
- wfm.feed_history_from_server(history).await
230
- }
231
- .boxed()
232
- })
233
- .await?;
234
- Ok(activation)
235
- } else {
236
- // Create a new workflow machines instance for this workflow, initialize it, and
237
- // track it.
238
- let metrics = parent_metrics.with_new_attrs([workflow_type(wf_type.to_string())]);
239
- let mut wfm = WorkflowManager::new(
240
- history,
241
- namespace.to_owned(),
242
- workflow_id.to_owned(),
243
- wf_type.to_owned(),
244
- run_id.to_owned(),
245
- metrics.clone(),
246
- );
247
- match wfm.get_next_activation().await {
248
- Ok(activation) => {
249
- if activation.jobs.is_empty() {
250
- Err(WFMachinesError::Fatal(
251
- "Machines created with no jobs".to_string(),
252
- ))
253
- } else {
254
- self.runs
255
- .write()
256
- .insert(run_id.to_string(), ManagedRun::new(wfm, metrics));
257
- Ok(activation)
258
- }
259
- }
260
- Err(e) => Err(e),
261
- }
262
- }
263
- }
264
-
265
- pub async fn access<F, Fout>(&self, run_id: &str, mutator: F) -> Result<Fout>
266
- where
267
- F: for<'a> FnOnce(&'a mut WorkflowManager) -> BoxFuture<Result<Fout>>,
268
- Fout: Send + Debug,
269
- {
270
- // TODO: Slightly less than ideal. We must avoid holding the read lock on the overall
271
- // machine map while async-ly mutating the inner machine. So, we clone the inner ArcMutex.
272
- // We should restructure things to avoid the top-level lock on the map.
273
-
274
- let wfm = {
275
- let readlock = self.runs.read();
276
- let m = readlock
277
- .get(run_id)
278
- .ok_or_else(|| WFMachinesError::Fatal("Missing workflow machines".to_string()))?;
279
- m.wfm.clone()
280
- };
281
-
282
- let res = mutator(&mut wfm.lock()).await;
283
- res
284
- }
285
-
286
- pub fn access_sync<F, Fout>(
287
- &self,
288
- run_id: &str,
289
- mutator: F,
290
- ) -> Result<Fout, WorkflowMissingError>
291
- where
292
- F: for<'a> FnOnce(&'a mut WorkflowManager) -> Fout,
293
- Fout: Send + Debug,
294
- {
295
- let readlock = self.runs.read();
296
- let m = readlock.get(run_id).ok_or_else(|| WorkflowMissingError {
297
- run_id: run_id.to_string(),
298
- })?;
299
- let mut wfm_mutex = m.wfm.lock();
300
- Ok(mutator(&mut wfm_mutex))
301
- }
302
-
303
- /// Remove the workflow with the provided run id from management
304
- pub fn evict(&self, run_id: &str) -> Option<ValidPollWFTQResponse> {
305
- let val = self.runs.write().remove(run_id);
306
- val.and_then(|v| v.buffered_resp)
307
- }
308
-
309
- /// Clear and return any buffered polling response for this run ID
310
- pub fn take_buffered_poll(&self, run_id: &str) -> Option<ValidPollWFTQResponse> {
311
- let mut writelock = self.runs.write();
312
- let val = writelock.get_mut(run_id);
313
- val.and_then(|v| v.buffered_resp.take())
314
- }
315
-
316
- /// Sounds the total number of outstanding workflow tasks
317
- pub fn outstanding_wft(&self) -> usize {
318
- self.runs
319
- .read()
320
- .iter()
321
- .filter(|(_, run)| run.wft.is_some())
322
- .count()
323
- }
324
-
325
- /// Returns number of currently cached workflows
326
- pub fn cached_workflows(&self) -> usize {
327
- self.runs.read().len()
328
- }
329
-
330
- /// Returns true if any outstanding activation contains an eviction
331
- pub fn are_outstanding_evictions(&self) -> bool {
332
- self.runs
333
- .read()
334
- .values()
335
- .any(|mr| mr.activation.map(|a| a.has_eviction()).unwrap_or_default())
336
- }
337
- }
338
-
339
- #[cfg(test)]
340
- mod tests {
341
- use super::*;
342
- use crate::test_help::canned_histories;
343
- use tokio::sync::Barrier;
344
-
345
- // We test mostly error paths here since the happy paths are well covered by the tests of the
346
- // core sdk itself, and setting up the fake data is onerous here. If we make the concurrency
347
- // manager generic, testing the happy path is simpler.
348
-
349
- #[tokio::test]
350
- async fn returns_errors_on_creation() {
351
- let mgr = WorkflowConcurrencyManager::new();
352
- let res = mgr
353
- .create_or_update(
354
- "some_run_id",
355
- HistoryUpdate::new_from_events(vec![], 0),
356
- "fake_wf_id",
357
- "fake_namespace",
358
- "fake_wf_type",
359
- &Default::default(),
360
- )
361
- .await;
362
- // Should whine that the machines have nothing to do (history empty)
363
- assert_matches!(res.unwrap_err(), WFMachinesError::Fatal { .. });
364
- }
365
-
366
- /// This test makes sure that if we're stuck on an await within the machine mutator we don't
367
- /// cause a deadlock if a write happens during that. This test will hang without proper
368
- /// implementation.
369
- #[tokio::test]
370
- async fn aba_deadlock_prevented() {
371
- let run_id = "some_run_id";
372
- let timer_hist = canned_histories::single_timer("t");
373
- let access_barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
374
- let wft = timer_hist.get_history_info(1).unwrap();
375
-
376
- let mgr = WorkflowConcurrencyManager::new();
377
- mgr.create_or_update(
378
- run_id,
379
- wft.clone().into(),
380
- "fake_wf_id",
381
- "fake_namespace",
382
- "fake_wf_type",
383
- &Default::default(),
384
- )
385
- .await
386
- .unwrap();
387
- // Perform access which blocks
388
- let access_fut = mgr.access(run_id, |_wfm| {
389
- async {
390
- // Wait to make sure access has started
391
- access_barr.wait().await;
392
- // Wait to make sure write has finished
393
- access_barr.wait().await;
394
- Ok(())
395
- }
396
- .boxed()
397
- });
398
- let write_fut = async {
399
- // Wait to make sure access has started
400
- access_barr.wait().await;
401
- // Now try writing
402
- mgr.create_or_update(
403
- "different_run_id",
404
- wft.clone().into(),
405
- "fake_wf_id",
406
- "fake_namespace",
407
- "fake_wf_type",
408
- &Default::default(),
409
- )
410
- .await
411
- .unwrap();
412
- // Indicate write has finished
413
- access_barr.wait().await;
414
- };
415
- let (r1, _) = tokio::join!(access_fut, write_fut);
416
- r1.unwrap();
417
- }
418
- }