@temporalio/core-bridge 1.5.2 → 1.6.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 (153) hide show
  1. package/Cargo.lock +255 -48
  2. package/package.json +4 -4
  3. package/releases/aarch64-apple-darwin/index.node +0 -0
  4. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  5. package/releases/x86_64-apple-darwin/index.node +0 -0
  6. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  7. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  8. package/sdk-core/.buildkite/pipeline.yml +1 -3
  9. package/sdk-core/.cargo/config.toml +5 -2
  10. package/sdk-core/.github/workflows/heavy.yml +28 -0
  11. package/sdk-core/Cargo.toml +1 -1
  12. package/sdk-core/README.md +9 -5
  13. package/sdk-core/client/src/lib.rs +211 -36
  14. package/sdk-core/client/src/raw.rs +1 -1
  15. package/sdk-core/client/src/retry.rs +32 -20
  16. package/sdk-core/core/Cargo.toml +23 -9
  17. package/sdk-core/core/src/abstractions.rs +11 -0
  18. package/sdk-core/core/src/core_tests/activity_tasks.rs +6 -5
  19. package/sdk-core/core/src/core_tests/local_activities.rs +263 -22
  20. package/sdk-core/core/src/core_tests/queries.rs +2 -2
  21. package/sdk-core/core/src/core_tests/workflow_tasks.rs +249 -5
  22. package/sdk-core/core/src/ephemeral_server/mod.rs +5 -6
  23. package/sdk-core/core/src/lib.rs +2 -0
  24. package/sdk-core/core/src/protosext/mod.rs +1 -1
  25. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  26. package/sdk-core/core/src/telemetry/mod.rs +23 -8
  27. package/sdk-core/core/src/test_help/mod.rs +8 -1
  28. package/sdk-core/core/src/worker/activities/local_activities.rs +259 -125
  29. package/sdk-core/core/src/worker/activities.rs +3 -2
  30. package/sdk-core/core/src/worker/mod.rs +53 -26
  31. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  32. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  33. package/sdk-core/core/src/worker/workflow/history_update.rs +835 -277
  34. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -17
  35. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +3 -5
  36. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -2
  37. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +3 -5
  38. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -2
  39. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -2
  40. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -2
  41. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +73 -51
  42. package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -3
  43. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -4
  44. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -2
  45. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +3 -5
  46. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +6 -7
  47. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  48. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -4
  49. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  50. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +89 -58
  51. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -7
  52. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +21 -9
  53. package/sdk-core/core/src/worker/workflow/managed_run.rs +1021 -360
  54. package/sdk-core/core/src/worker/workflow/mod.rs +306 -346
  55. package/sdk-core/core/src/worker/workflow/run_cache.rs +29 -53
  56. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  57. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  58. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +115 -0
  59. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  60. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +444 -714
  61. package/sdk-core/core-api/Cargo.toml +2 -0
  62. package/sdk-core/core-api/src/errors.rs +1 -34
  63. package/sdk-core/core-api/src/lib.rs +6 -2
  64. package/sdk-core/core-api/src/worker.rs +14 -1
  65. package/sdk-core/etc/deps.svg +115 -140
  66. package/sdk-core/etc/regen-depgraph.sh +5 -0
  67. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -6
  68. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -3
  69. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  70. package/sdk-core/protos/api_upstream/Makefile +5 -5
  71. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  72. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  73. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  74. package/sdk-core/protos/api_upstream/go.mod +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  76. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +12 -19
  77. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
  78. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  79. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -2
  80. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  81. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +3 -3
  82. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -2
  83. package/sdk-core/protos/api_upstream/temporal/api/{update/v1/message.proto → enums/v1/interaction_type.proto} +11 -18
  84. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  85. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  86. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  87. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  88. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  89. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +2 -13
  90. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  91. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  92. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  93. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  94. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -19
  95. package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -2
  98. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  101. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  103. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +13 -8
  106. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  107. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  108. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  109. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  110. package/sdk-core/sdk/Cargo.toml +4 -3
  111. package/sdk-core/sdk/src/lib.rs +87 -21
  112. package/sdk-core/sdk/src/workflow_future.rs +7 -12
  113. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  114. package/sdk-core/sdk-core-protos/build.rs +36 -2
  115. package/sdk-core/sdk-core-protos/src/history_builder.rs +26 -19
  116. package/sdk-core/sdk-core-protos/src/history_info.rs +4 -0
  117. package/sdk-core/sdk-core-protos/src/lib.rs +78 -34
  118. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  119. package/sdk-core/test-utils/Cargo.toml +3 -1
  120. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  121. package/sdk-core/test-utils/src/lib.rs +50 -18
  122. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  123. package/sdk-core/test-utils/src/workflows.rs +29 -0
  124. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  125. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +114 -7
  126. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -2
  127. package/sdk-core/tests/integ_tests/metrics_tests.rs +1 -1
  128. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -39
  129. package/sdk-core/tests/integ_tests/queries_tests.rs +2 -127
  130. package/sdk-core/tests/integ_tests/visibility_tests.rs +52 -5
  131. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +74 -1
  132. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +5 -13
  133. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +1 -1
  134. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +2 -10
  135. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +69 -197
  136. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +4 -28
  137. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  138. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +14 -14
  139. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -19
  140. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -19
  141. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests.rs +5 -6
  143. package/sdk-core/tests/main.rs +2 -12
  144. package/sdk-core/tests/runner.rs +71 -34
  145. package/sdk-core/tests/wf_input_replay.rs +32 -0
  146. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  147. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  148. package/sdk-core/bridge-ffi/build.rs +0 -25
  149. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  150. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  151. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  152. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  153. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -2,16 +2,18 @@ use assert_matches::assert_matches;
2
2
  use futures::{future::join_all, sink, stream::FuturesUnordered, StreamExt};
3
3
  use std::time::{Duration, Instant};
4
4
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
5
- use temporal_sdk::{ActContext, ActivityOptions, WfContext};
5
+ use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
6
6
  use temporal_sdk_core_protos::coresdk::{
7
7
  activity_result::ActivityExecutionResult, activity_task::activity_task as act_task,
8
8
  workflow_commands::ActivityCancellationType, ActivityTaskCompletion, AsJsonPayloadExt,
9
9
  };
10
- use temporal_sdk_core_test_utils::CoreWfStarter;
10
+ use temporal_sdk_core_test_utils::{workflows::la_problem_workflow, CoreWfStarter};
11
+
12
+ mod fuzzy_workflow;
11
13
 
12
14
  #[tokio::test]
13
15
  async fn activity_load() {
14
- const CONCURRENCY: usize = 1000;
16
+ const CONCURRENCY: usize = 512;
15
17
 
16
18
  let mut starter = CoreWfStarter::new("activity_load");
17
19
  starter
@@ -54,7 +56,7 @@ async fn activity_load() {
54
56
  worker.register_wf(wf_type.to_owned(), wf_fn);
55
57
  join_all((0..CONCURRENCY).map(|i| {
56
58
  let worker = &worker;
57
- let wf_id = format!("activity_load_{}", i);
59
+ let wf_id = format!("activity_load_{i}");
58
60
  async move {
59
61
  worker
60
62
  .submit_wf(
@@ -153,7 +155,7 @@ async fn workflow_load() {
153
155
 
154
156
  let mut workflow_handles = vec![];
155
157
  for i in 0..num_workflows {
156
- let wfid = format!("{}_{}", wf_name, i);
158
+ let wfid = format!("{wf_name}_{i}");
157
159
  let rid = worker
158
160
  .submit_wf(
159
161
  wfid.clone(),
@@ -171,7 +173,7 @@ async fn workflow_load() {
171
173
  let sends: FuturesUnordered<_> = (0..num_workflows)
172
174
  .map(|i| {
173
175
  client.signal_workflow_execution(
174
- format!("{}_{}", wf_name, i),
176
+ format!("{wf_name}_{i}"),
175
177
  "".to_string(),
176
178
  SIGNAME.to_string(),
177
179
  None,
@@ -187,5 +189,110 @@ async fn workflow_load() {
187
189
  tokio::time::sleep(Duration::from_secs(2)).await;
188
190
  }
189
191
  };
190
- tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}};
192
+ tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}}
193
+ }
194
+
195
+ #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
196
+ async fn evict_while_la_running_no_interference() {
197
+ let wf_name = "evict_while_la_running_no_interference";
198
+ let mut starter = CoreWfStarter::new(wf_name);
199
+ starter.max_local_at(20);
200
+ starter.max_cached_workflows(20);
201
+ // Though it doesn't make sense to set wft higher than cached workflows, leaving this commented
202
+ // introduces more instability that can be useful in the test.
203
+ // starter.max_wft(20);
204
+ let mut worker = starter.worker().await;
205
+
206
+ worker.register_wf(wf_name.to_owned(), la_problem_workflow);
207
+ worker.register_activity("delay", |_: ActContext, _: String| async {
208
+ tokio::time::sleep(Duration::from_secs(15)).await;
209
+ Ok(())
210
+ });
211
+
212
+ let client = starter.get_client().await;
213
+ let subfs = FuturesUnordered::new();
214
+ for i in 1..100 {
215
+ let wf_id = format!("{wf_name}-{i}");
216
+ let run_id = worker
217
+ .submit_wf(
218
+ &wf_id,
219
+ wf_name.to_owned(),
220
+ vec![],
221
+ WorkflowOptions::default(),
222
+ )
223
+ .await
224
+ .unwrap();
225
+ let cw = worker.core_worker.clone();
226
+ let client = client.clone();
227
+ subfs.push(async move {
228
+ // Evict the workflow
229
+ tokio::time::sleep(Duration::from_secs(1)).await;
230
+ cw.request_workflow_eviction(&run_id);
231
+ // Wake up workflow by sending signal
232
+ client
233
+ .signal_workflow_execution(
234
+ wf_id,
235
+ run_id.clone(),
236
+ "whaatever".to_string(),
237
+ None,
238
+ None,
239
+ )
240
+ .await
241
+ .unwrap();
242
+ });
243
+ }
244
+ let runf = async {
245
+ worker.run_until_done().await.unwrap();
246
+ };
247
+ tokio::join!(subfs.collect::<Vec<_>>(), runf);
248
+ }
249
+
250
+ pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()> {
251
+ for _ in 0..120 {
252
+ let mut futs = vec![];
253
+ for _ in 0..100 {
254
+ futs.push(ctx.timer(Duration::from_millis(100)));
255
+ }
256
+ join_all(futs).await;
257
+ }
258
+ Ok(().into())
259
+ }
260
+
261
+ #[tokio::test]
262
+ async fn can_paginate_long_history() {
263
+ let wf_name = "can_paginate_long_history";
264
+ let mut starter = CoreWfStarter::new(wf_name);
265
+ // Do not use sticky queues so we are forced to paginate once history gets long
266
+ starter.max_cached_workflows(0);
267
+
268
+ let mut worker = starter.worker().await;
269
+ worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
270
+ let run_id = worker
271
+ .submit_wf(
272
+ wf_name.to_owned(),
273
+ wf_name.to_owned(),
274
+ vec![],
275
+ WorkflowOptions::default(),
276
+ )
277
+ .await
278
+ .unwrap();
279
+ let client = starter.get_client().await;
280
+ tokio::spawn(async move {
281
+ loop {
282
+ for _ in 0..10 {
283
+ client
284
+ .signal_workflow_execution(
285
+ wf_name.to_owned(),
286
+ run_id.clone(),
287
+ "sig".to_string(),
288
+ None,
289
+ None,
290
+ )
291
+ .await
292
+ .unwrap();
293
+ }
294
+ tokio::time::sleep(Duration::from_secs(3)).await;
295
+ }
296
+ });
297
+ worker.run_until_done().await.unwrap();
191
298
  }
@@ -13,7 +13,10 @@ use temporal_sdk_core_protos::{
13
13
  workflow_completion::WorkflowActivationCompletion,
14
14
  ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
15
15
  },
16
- temporal::api::common::v1::{Payload, RetryPolicy},
16
+ temporal::api::{
17
+ common::v1::{Payload, RetryPolicy},
18
+ enums::v1::TimeoutType,
19
+ },
17
20
  };
18
21
  use temporal_sdk_core_test_utils::{
19
22
  init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
@@ -196,7 +199,7 @@ async fn activity_doesnt_heartbeat_hits_timeout_then_completes() {
196
199
  ..Default::default()
197
200
  })
198
201
  .await;
199
- assert!(res.timed_out());
202
+ assert_eq!(res.timed_out(), Some(TimeoutType::Heartbeat));
200
203
  Ok(().into())
201
204
  });
202
205
 
@@ -22,7 +22,7 @@ async fn prometheus_metrics_exported() {
22
22
  .await
23
23
  .unwrap();
24
24
 
25
- let body = reqwest::get(format!("http://{}/metrics", addr))
25
+ let body = reqwest::get(format!("http://{addr}/metrics"))
26
26
  .await
27
27
  .unwrap()
28
28
  .text()
@@ -1,8 +1,5 @@
1
1
  use assert_matches::assert_matches;
2
- use futures::future::join_all;
3
2
  use std::time::Duration;
4
- use temporal_client::WorkflowOptions;
5
- use temporal_sdk::{WfContext, WorkflowResult};
6
3
  use temporal_sdk_core_protos::coresdk::{
7
4
  activity_task::activity_task as act_task,
8
5
  workflow_activation::{workflow_activation_job, FireTimer, WorkflowActivationJob},
@@ -11,7 +8,7 @@ use temporal_sdk_core_protos::coresdk::{
11
8
  IntoCompletion,
12
9
  };
13
10
  use temporal_sdk_core_test_utils::{
14
- init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
11
+ init_core_and_create_wf, schedule_activity_cmd, WorkerTestHelpers,
15
12
  };
16
13
  use tokio::time::timeout;
17
14
 
@@ -96,38 +93,3 @@ async fn out_of_order_completion_doesnt_hang() {
96
93
 
97
94
  jh.await.unwrap();
98
95
  }
99
-
100
- pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()> {
101
- for _ in 0..20 {
102
- let mut futs = vec![];
103
- for _ in 0..1000 {
104
- futs.push(ctx.timer(Duration::from_millis(100)));
105
- }
106
- join_all(futs).await;
107
- }
108
- Ok(().into())
109
- }
110
-
111
- // Ignored for now because I can't actually get this to produce pages. Need to generate some
112
- // large payloads I think.
113
- #[tokio::test]
114
- #[ignore]
115
- async fn can_paginate_long_history() {
116
- let wf_name = "can_paginate_long_history";
117
- let mut starter = CoreWfStarter::new(wf_name);
118
- // Do not use sticky queues so we are forced to paginate once history gets long
119
- starter.max_cached_workflows(0);
120
-
121
- let mut worker = starter.worker().await;
122
- worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
123
- worker
124
- .submit_wf(
125
- wf_name.to_owned(),
126
- wf_name.to_owned(),
127
- vec![],
128
- WorkflowOptions::default(),
129
- )
130
- .await
131
- .unwrap();
132
- worker.run_until_done().await.unwrap();
133
- }
@@ -10,7 +10,7 @@ use temporal_sdk_core_protos::{
10
10
  },
11
11
  temporal::api::{failure::v1::Failure, query::v1::WorkflowQuery},
12
12
  };
13
- use temporal_sdk_core_test_utils::{init_core_and_create_wf, CoreWfStarter, WorkerTestHelpers};
13
+ use temporal_sdk_core_test_utils::{init_core_and_create_wf, WorkerTestHelpers};
14
14
 
15
15
  #[tokio::test]
16
16
  async fn simple_query_legacy() {
@@ -112,7 +112,7 @@ async fn simple_query_legacy() {
112
112
  async fn query_after_execution_complete(#[case] do_evict: bool) {
113
113
  let query_resp = b"response";
114
114
  let mut starter =
115
- init_core_and_create_wf(&format!("query_after_execution_complete-{}", do_evict)).await;
115
+ init_core_and_create_wf(&format!("query_after_execution_complete-{do_evict}")).await;
116
116
  let core = &starter.get_worker().await;
117
117
  let workflow_id = &starter.get_task_queue().to_string();
118
118
 
@@ -208,131 +208,6 @@ async fn query_after_execution_complete(#[case] do_evict: bool) {
208
208
  core.shutdown().await;
209
209
  }
210
210
 
211
- #[ignore]
212
- #[tokio::test]
213
- async fn repros_query_dropped_on_floor() {
214
- // This test reliably repros the server dropping one of the two simultaneously issued queries.
215
- let q1_resp = b"query_1_resp";
216
- let q2_resp = b"query_2_resp";
217
- let mut wf_starter = CoreWfStarter::new("repros_query_dropped_on_floor");
218
- // Easiest way I discovered to reliably trigger new query path is with a WFT timeout
219
- wf_starter.wft_timeout(Duration::from_secs(1));
220
- let core = wf_starter.get_worker().await;
221
- let task_q = wf_starter.get_task_queue().to_string();
222
- wf_starter.start_wf().await;
223
- let client = wf_starter.get_client().await;
224
-
225
- let task = core.poll_workflow_activation().await.unwrap();
226
- core.complete_timer(&task.run_id, 1, Duration::from_millis(500))
227
- .await;
228
-
229
- // Poll for a task we will time out
230
- let task = core.poll_workflow_activation().await.unwrap();
231
- tokio::time::sleep(Duration::from_secs(2)).await;
232
- // Complete now-timed-out task (add a new timer)
233
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
234
- task.run_id.clone(),
235
- vec![],
236
- ))
237
- .await
238
- .unwrap();
239
-
240
- let run_id = task.run_id.to_string();
241
- let q1_fut = async {
242
- client
243
- .query_workflow_execution(
244
- task_q.clone(),
245
- run_id,
246
- WorkflowQuery {
247
- query_type: "query_1".to_string(),
248
- query_args: Some(b"hi 1".into()),
249
- header: None,
250
- },
251
- )
252
- .await
253
- .unwrap()
254
- };
255
- let run_id = task.run_id.to_string();
256
- let q2_fut = async {
257
- client
258
- .query_workflow_execution(
259
- task_q.clone(),
260
- run_id,
261
- WorkflowQuery {
262
- query_type: "query_2".to_string(),
263
- query_args: Some(b"hi 2".into()),
264
- header: None,
265
- },
266
- )
267
- .await
268
- .unwrap()
269
- };
270
- let workflow_completions_future = async {
271
- let mut seen_q1 = false;
272
- let mut seen_q2 = false;
273
- while !seen_q1 || !seen_q2 {
274
- let task = core.poll_workflow_activation().await.unwrap();
275
-
276
- if matches!(
277
- task.jobs[0],
278
- WorkflowActivationJob {
279
- variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
280
- }
281
- ) {
282
- let task = core.poll_workflow_activation().await.unwrap();
283
- core.complete_timer(&task.run_id, 1, Duration::from_millis(500))
284
- .await;
285
- continue;
286
- }
287
-
288
- if matches!(
289
- task.jobs[0],
290
- WorkflowActivationJob {
291
- variant: Some(workflow_activation_job::Variant::FireTimer(_)),
292
- }
293
- ) {
294
- // If we get the timer firing after replay, be done.
295
- core.complete_execution(&task.run_id).await;
296
- }
297
-
298
- // There should be a query job (really, there should be both... server only sends one?)
299
- let query = assert_matches!(
300
- task.jobs.as_slice(),
301
- [WorkflowActivationJob {
302
- variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
303
- }] => q
304
- );
305
- let resp = if query.query_type == "query_1" {
306
- seen_q1 = true;
307
- q1_resp
308
- } else {
309
- seen_q2 = true;
310
- q2_resp
311
- };
312
- // Complete the query
313
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
314
- task.run_id,
315
- vec![QueryResult {
316
- query_id: query.query_id.clone(),
317
- variant: Some(
318
- QuerySuccess {
319
- response: Some(resp.into()),
320
- }
321
- .into(),
322
- ),
323
- }
324
- .into()],
325
- ))
326
- .await
327
- .unwrap();
328
- }
329
- };
330
- let (q1_res, q2_res, _) = tokio::join!(q1_fut, q2_fut, workflow_completions_future);
331
- // Ensure query responses are as expected
332
- assert_eq!(&q1_res.unwrap()[0].data, q1_resp);
333
- assert_eq!(&q2_res.unwrap()[0].data, q2_resp);
334
- }
335
-
336
211
  #[tokio::test]
337
212
  async fn fail_legacy_query() {
338
213
  let query_err = "oh no broken";
@@ -1,8 +1,8 @@
1
1
  use assert_matches::assert_matches;
2
2
  use std::{sync::Arc, time::Duration};
3
3
  use temporal_client::{
4
- ListClosedFilters, ListOpenFilters, Namespace, StartTimeFilter, WorkflowClientTrait,
5
- WorkflowExecutionFilter, WorkflowOptions,
4
+ ListClosedFilters, ListOpenFilters, Namespace, RegisterNamespaceOptions, StartTimeFilter,
5
+ WorkflowClientTrait, WorkflowExecutionFilter,
6
6
  };
7
7
  use temporal_sdk_core_protos::coresdk::workflow_activation::{
8
8
  workflow_activation_job, WorkflowActivationJob,
@@ -10,6 +10,7 @@ use temporal_sdk_core_protos::coresdk::workflow_activation::{
10
10
  use temporal_sdk_core_test_utils::{
11
11
  get_integ_server_options, CoreWfStarter, WorkerTestHelpers, NAMESPACE,
12
12
  };
13
+ use tokio::time::sleep;
13
14
 
14
15
  #[tokio::test]
15
16
  async fn client_list_open_closed_workflow_executions() {
@@ -22,9 +23,7 @@ async fn client_list_open_closed_workflow_executions() {
22
23
  let latest = earliest + Duration::from_secs(60);
23
24
 
24
25
  // start workflow
25
- let run_id = starter
26
- .start_wf_with_id(wf_name.to_owned(), WorkflowOptions::default())
27
- .await;
26
+ let run_id = starter.start_wf_with_id(wf_name.to_owned()).await;
28
27
  let task = core.poll_workflow_activation().await.unwrap();
29
28
  assert_matches!(
30
29
  task.jobs.as_slice(),
@@ -52,6 +51,7 @@ async fn client_list_open_closed_workflow_executions() {
52
51
 
53
52
  // Complete workflow
54
53
  core.complete_execution(&task.run_id).await;
54
+ core.shutdown().await;
55
55
 
56
56
  // List above CLOSED workflow
57
57
  let start_time_filter = StartTimeFilter {
@@ -76,6 +76,53 @@ async fn client_list_open_closed_workflow_executions() {
76
76
  assert_eq!(workflow.execution.as_ref().unwrap().workflow_id, wf_name);
77
77
  }
78
78
 
79
+ #[tokio::test]
80
+ async fn client_create_namespace() {
81
+ let client = Arc::new(
82
+ get_integ_server_options()
83
+ .connect(NAMESPACE.to_owned(), None, None)
84
+ .await
85
+ .expect("Must connect"),
86
+ );
87
+
88
+ let register_options = RegisterNamespaceOptions::builder()
89
+ .namespace("test-create-namespace")
90
+ .description("it's alive")
91
+ .build()
92
+ .unwrap();
93
+
94
+ client
95
+ .register_namespace(register_options.clone())
96
+ .await
97
+ .unwrap();
98
+
99
+ //#Hack, not sure how else to wait for a proper response. RegisterNamespace isn't safe to read
100
+ //after write
101
+ let mut attempts = 0;
102
+ let wait_time = Duration::from_secs(1);
103
+ loop {
104
+ attempts += 1;
105
+ let resp = client
106
+ .describe_namespace(Namespace::Name(register_options.namespace.clone()))
107
+ .await;
108
+
109
+ match resp {
110
+ Ok(n) => {
111
+ let namespace_info = n.namespace_info.unwrap();
112
+ assert_eq!(namespace_info.name, register_options.namespace);
113
+ assert_eq!(namespace_info.description, register_options.description);
114
+ return;
115
+ }
116
+ _ => {
117
+ if attempts == 12 {
118
+ panic!("failed to query registered namespace");
119
+ }
120
+ sleep(wait_time).await
121
+ }
122
+ }
123
+ }
124
+ }
125
+
79
126
  #[tokio::test]
80
127
  async fn client_describe_namespace() {
81
128
  let client = Arc::new(
@@ -1,3 +1,4 @@
1
+ use anyhow::anyhow;
1
2
  use assert_matches::assert_matches;
2
3
  use std::time::Duration;
3
4
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
@@ -205,6 +206,78 @@ async fn activity_non_retryable_failure() {
205
206
  core.complete_execution(&task.run_id).await;
206
207
  }
207
208
 
209
+ #[tokio::test]
210
+ async fn activity_non_retryable_failure_with_error() {
211
+ let mut starter = init_core_and_create_wf("activity_non_retryable_failure").await;
212
+ let core = starter.get_worker().await;
213
+ let task_q = starter.get_task_queue();
214
+ let activity_id = "act-1";
215
+ let task = core.poll_workflow_activation().await.unwrap();
216
+ // Complete workflow task and schedule activity
217
+ core.complete_workflow_activation(
218
+ schedule_activity_cmd(
219
+ 0,
220
+ task_q,
221
+ activity_id,
222
+ ActivityCancellationType::TryCancel,
223
+ Duration::from_secs(60),
224
+ Duration::from_secs(60),
225
+ )
226
+ .into_completion(task.run_id),
227
+ )
228
+ .await
229
+ .unwrap();
230
+ // Poll activity and verify that it's been scheduled with correct parameters
231
+ let task = core.poll_activity_task().await.unwrap();
232
+ assert_matches!(
233
+ task.variant,
234
+ Some(act_task::Variant::Start(start_activity)) => {
235
+ assert_eq!(start_activity.activity_type, "test_activity".to_string())
236
+ }
237
+ );
238
+ // Fail activity with non-retryable error
239
+ let failure = Failure::application_failure_from_error(anyhow!("activity failed"), true);
240
+ core.complete_activity_task(ActivityTaskCompletion {
241
+ task_token: task.task_token,
242
+ result: Some(ActivityExecutionResult::fail(failure.clone())),
243
+ })
244
+ .await
245
+ .unwrap();
246
+ // Poll workflow task and verify that activity has failed.
247
+ let task = core.poll_workflow_activation().await.unwrap();
248
+ assert_matches!(
249
+ task.jobs.as_slice(),
250
+ [
251
+ WorkflowActivationJob {
252
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(
253
+ ResolveActivity {seq, result: Some(ActivityResolution{
254
+ status: Some(act_res::Status::Failed(activity_result::Failure{
255
+ failure: Some(f),
256
+ }))})}
257
+ )),
258
+ },
259
+ ] => {
260
+ assert_eq!(*seq, 0);
261
+ assert_eq!(f, &Failure{
262
+ message: "Activity task failed".to_owned(),
263
+ cause: Some(Box::new(failure)),
264
+ failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
265
+ activity_id: "act-1".to_owned(),
266
+ activity_type: Some(ActivityType {
267
+ name: "test_activity".to_owned(),
268
+ }),
269
+ scheduled_event_id: 5,
270
+ started_event_id: 6,
271
+ identity: "integ_tester".to_owned(),
272
+ retry_state: RetryState::NonRetryableFailure as i32,
273
+ })),
274
+ ..Default::default()
275
+ });
276
+ }
277
+ );
278
+ core.complete_execution(&task.run_id).await;
279
+ }
280
+
208
281
  #[tokio::test]
209
282
  async fn activity_retry() {
210
283
  let mut starter = init_core_and_create_wf("activity_retry").await;
@@ -822,7 +895,7 @@ async fn it_can_complete_async() {
822
895
  Some(act_res::Status::Completed(activity_result::Success { result })) => result
823
896
  .map(|p| String::from_json_payload(&p).unwrap())
824
897
  .unwrap(),
825
- _ => panic!("activity task failed {:?}", activity_resolution),
898
+ _ => panic!("activity task failed {activity_resolution:?}"),
826
899
  };
827
900
 
828
901
  assert_eq!(&res, async_response);
@@ -1,5 +1,5 @@
1
1
  use std::time::Duration;
2
- use temporal_client::{WorkflowClientTrait, WorkflowOptions};
2
+ use temporal_client::WorkflowClientTrait;
3
3
  use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
4
4
  use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowExecutionStatus;
5
5
  use temporal_sdk_core_test_utils::CoreWfStarter;
@@ -24,22 +24,14 @@ async fn cancel_during_timer() {
24
24
  let mut worker = starter.worker().await;
25
25
  let client = starter.get_client().await;
26
26
  worker.register_wf(wf_name.to_string(), cancelled_wf);
27
-
28
- worker
29
- .submit_wf(
30
- wf_name.to_owned(),
31
- wf_name.to_owned(),
32
- vec![],
33
- WorkflowOptions::default(),
34
- )
35
- .await
36
- .unwrap();
27
+ starter.start_with_worker(wf_name, &mut worker).await;
28
+ let wf_id = starter.get_task_queue().to_string();
37
29
 
38
30
  let canceller = async {
39
31
  tokio::time::sleep(Duration::from_millis(500)).await;
40
32
  // Cancel the workflow externally
41
33
  client
42
- .cancel_workflow_execution(wf_name.to_string(), None, "Dieee".to_string(), None)
34
+ .cancel_workflow_execution(wf_id.clone(), None, "Dieee".to_string(), None)
43
35
  .await
44
36
  .unwrap();
45
37
  };
@@ -47,7 +39,7 @@ async fn cancel_during_timer() {
47
39
  let (_, res) = tokio::join!(canceller, worker.run_until_done());
48
40
  res.unwrap();
49
41
  let desc = client
50
- .describe_workflow_execution(wf_name.to_string(), None)
42
+ .describe_workflow_execution(wf_id, None)
51
43
  .await
52
44
  .unwrap();
53
45
 
@@ -44,7 +44,7 @@ async fn continue_as_new_multiple_concurrent() {
44
44
  let mut worker = starter.worker().await;
45
45
  worker.register_wf(wf_name.to_string(), continue_as_new_wf);
46
46
 
47
- let wf_names = (1..=20).map(|i| format!("{}-{}", wf_name, i));
47
+ let wf_names = (1..=20).map(|i| format!("{wf_name}-{i}"));
48
48
  for name in wf_names.clone() {
49
49
  worker
50
50
  .submit_wf(
@@ -2,7 +2,7 @@ use std::{
2
2
  sync::atomic::{AtomicUsize, Ordering},
3
3
  time::Duration,
4
4
  };
5
- use temporal_client::WorkflowOptions;
5
+
6
6
  use temporal_sdk::{ActivityOptions, WfContext, WorkflowResult};
7
7
  use temporal_sdk_core_test_utils::CoreWfStarter;
8
8
 
@@ -39,15 +39,7 @@ async fn test_determinism_error_then_recovers() {
39
39
  let mut worker = starter.worker().await;
40
40
 
41
41
  worker.register_wf(wf_name.to_owned(), timer_wf_nondeterministic);
42
- worker
43
- .submit_wf(
44
- wf_name.to_owned(),
45
- wf_name.to_owned(),
46
- vec![],
47
- WorkflowOptions::default(),
48
- )
49
- .await
50
- .unwrap();
42
+ starter.start_with_worker(wf_name, &mut worker).await;
51
43
  worker.run_until_done().await.unwrap();
52
44
  // 4 because we still add on the 3rd and final attempt
53
45
  assert_eq!(RUN_CT.load(Ordering::Relaxed), 4);