@temporalio/core-bridge 1.5.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -4
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -2,7 +2,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
 
@@ -36,18 +36,11 @@ pub async fn timer_wf_nondeterministic(ctx: WfContext) -> WorkflowResult<()> {
36
36
  async fn test_determinism_error_then_recovers() {
37
37
  let wf_name = "test_determinism_error_then_recovers";
38
38
  let mut starter = CoreWfStarter::new(wf_name);
39
+ starter.no_remote_activities();
39
40
  let mut worker = starter.worker().await;
40
41
 
41
42
  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();
43
+ starter.start_with_worker(wf_name, &mut worker).await;
51
44
  worker.run_until_done().await.unwrap();
52
45
  // 4 because we still add on the 3rd and final attempt
53
46
  assert_eq!(RUN_CT.load(Ordering::Relaxed), 4);
@@ -1,23 +1,27 @@
1
1
  use anyhow::anyhow;
2
2
  use futures::future::join_all;
3
- use futures_util::stream::{FuturesUnordered, StreamExt};
4
- use std::time::Duration;
5
- use temporal_client::{WorkflowClientTrait, WorkflowOptions};
3
+ use std::{
4
+ sync::atomic::{AtomicU8, Ordering},
5
+ time::Duration,
6
+ };
7
+ use temporal_client::WorkflowOptions;
6
8
  use temporal_sdk::{
7
- interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, ActivityOptions,
8
- CancellableFuture, LocalActivityOptions, WfContext, WorkflowResult,
9
+ interceptors::WorkerInterceptor, ActContext, ActivityCancelledError, CancellableFuture,
10
+ LocalActivityOptions, WfContext, WorkflowResult,
9
11
  };
10
12
  use temporal_sdk_core::replay::HistoryForReplay;
11
13
  use temporal_sdk_core_protos::{
12
14
  coresdk::{
13
- workflow_commands::ActivityCancellationType,
15
+ workflow_commands::workflow_command::Variant, workflow_commands::ActivityCancellationType,
16
+ workflow_completion, workflow_completion::workflow_activation_completion,
14
17
  workflow_completion::WorkflowActivationCompletion, AsJsonPayloadExt,
15
18
  },
16
- temporal::api::common::v1::RetryPolicy,
19
+ temporal::api::{common::v1::RetryPolicy, enums::v1::TimeoutType},
17
20
  TestHistoryBuilder,
18
21
  };
19
22
  use temporal_sdk_core_test_utils::{
20
- history_from_proto_binary, init_integ_telem, replay_sdk_worker, CoreWfStarter,
23
+ history_from_proto_binary, init_integ_telem, replay_sdk_worker, workflows::la_problem_workflow,
24
+ CoreWfStarter,
21
25
  };
22
26
  use tokio_util::sync::CancellationToken;
23
27
 
@@ -46,15 +50,7 @@ async fn one_local_activity() {
46
50
  worker.register_wf(wf_name.to_owned(), one_local_activity_wf);
47
51
  worker.register_activity("echo_activity", echo);
48
52
 
49
- worker
50
- .submit_wf(
51
- wf_name.to_owned(),
52
- wf_name.to_owned(),
53
- vec![],
54
- WorkflowOptions::default(),
55
- )
56
- .await
57
- .unwrap();
53
+ starter.start_with_worker(wf_name, &mut worker).await;
58
54
  worker.run_until_done().await.unwrap();
59
55
  }
60
56
 
@@ -77,15 +73,7 @@ async fn local_act_concurrent_with_timer() {
77
73
  worker.register_wf(wf_name.to_owned(), local_act_concurrent_with_timer_wf);
78
74
  worker.register_activity("echo_activity", echo);
79
75
 
80
- worker
81
- .submit_wf(
82
- wf_name.to_owned(),
83
- wf_name.to_owned(),
84
- vec![],
85
- WorkflowOptions::default(),
86
- )
87
- .await
88
- .unwrap();
76
+ starter.start_with_worker(wf_name, &mut worker).await;
89
77
  worker.run_until_done().await.unwrap();
90
78
  }
91
79
 
@@ -109,15 +97,7 @@ async fn local_act_then_timer_then_wait_result() {
109
97
  worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
110
98
  worker.register_activity("echo_activity", echo);
111
99
 
112
- worker
113
- .submit_wf(
114
- wf_name.to_owned(),
115
- wf_name.to_owned(),
116
- vec![],
117
- WorkflowOptions::default(),
118
- )
119
- .await
120
- .unwrap();
100
+ starter.start_with_worker(wf_name, &mut worker).await;
121
101
  worker.run_until_done().await.unwrap();
122
102
  }
123
103
 
@@ -125,7 +105,7 @@ async fn local_act_then_timer_then_wait_result() {
125
105
  async fn long_running_local_act_with_timer() {
126
106
  let wf_name = "long_running_local_act_with_timer";
127
107
  let mut starter = CoreWfStarter::new(wf_name);
128
- starter.wft_timeout(Duration::from_secs(1));
108
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
129
109
  let mut worker = starter.worker().await;
130
110
  worker.register_wf(wf_name.to_owned(), local_act_then_timer_then_wait);
131
111
  worker.register_activity("echo_activity", |_ctx: ActContext, str: String| async {
@@ -133,15 +113,7 @@ async fn long_running_local_act_with_timer() {
133
113
  Ok(str)
134
114
  });
135
115
 
136
- worker
137
- .submit_wf(
138
- wf_name.to_owned(),
139
- wf_name.to_owned(),
140
- vec![],
141
- WorkflowOptions::default(),
142
- )
143
- .await
144
- .unwrap();
116
+ starter.start_with_worker(wf_name, &mut worker).await;
145
117
  worker.run_until_done().await.unwrap();
146
118
  }
147
119
 
@@ -150,7 +122,7 @@ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
150
122
  .map(|i| {
151
123
  ctx.local_activity(LocalActivityOptions {
152
124
  activity_type: "echo_activity".to_string(),
153
- input: format!("Hi {}", i)
125
+ input: format!("Hi {i}")
154
126
  .as_json_payload()
155
127
  .expect("serializes fine"),
156
128
  ..Default::default()
@@ -171,15 +143,7 @@ async fn local_act_fanout() {
171
143
  worker.register_wf(wf_name.to_owned(), local_act_fanout_wf);
172
144
  worker.register_activity("echo_activity", echo);
173
145
 
174
- worker
175
- .submit_wf(
176
- wf_name.to_owned(),
177
- wf_name.to_owned(),
178
- vec![],
179
- WorkflowOptions::default(),
180
- )
181
- .await
182
- .unwrap();
146
+ starter.start_with_worker(wf_name, &mut worker).await;
183
147
  worker.run_until_done().await.unwrap();
184
148
  }
185
149
 
@@ -234,7 +198,7 @@ async fn local_act_retry_timer_backoff() {
234
198
  #[case::abandon(ActivityCancellationType::Abandon)]
235
199
  #[tokio::test]
236
200
  async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
237
- let wf_name = format!("cancel_immediate_{:?}", cancel_type);
201
+ let wf_name = format!("cancel_immediate_{cancel_type:?}");
238
202
  let mut starter = CoreWfStarter::new(&wf_name);
239
203
  let mut worker = starter.worker().await;
240
204
  worker.register_wf(&wf_name, move |ctx: WfContext| async move {
@@ -268,17 +232,10 @@ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
268
232
  }
269
233
  });
270
234
 
271
- worker
272
- .submit_wf(
273
- wf_name.to_owned(),
274
- wf_name.to_owned(),
275
- vec![],
276
- WorkflowOptions::default(),
277
- )
278
- .await
279
- .unwrap();
235
+ starter.start_with_worker(wf_name, &mut worker).await;
280
236
  worker
281
237
  .run_until_done_intercepted(Some(LACancellerInterceptor {
238
+ cancel_on_workflow_completed: false,
282
239
  token: manual_cancel,
283
240
  }))
284
241
  .await
@@ -287,12 +244,29 @@ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
287
244
 
288
245
  struct LACancellerInterceptor {
289
246
  token: CancellationToken,
247
+ cancel_on_workflow_completed: bool,
290
248
  }
291
249
  #[async_trait::async_trait(?Send)]
292
250
  impl WorkerInterceptor for LACancellerInterceptor {
293
- async fn on_workflow_activation_completion(&self, _: &WorkflowActivationCompletion) {}
251
+ async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
252
+ if !self.cancel_on_workflow_completed {
253
+ return;
254
+ }
255
+ if let Some(workflow_activation_completion::Status::Successful(
256
+ workflow_completion::Success { commands, .. },
257
+ )) = completion.status.as_ref()
258
+ {
259
+ if let Some(&Variant::CompleteWorkflowExecution(_)) =
260
+ commands.last().and_then(|v| v.variant.as_ref())
261
+ {
262
+ self.token.cancel();
263
+ }
264
+ }
265
+ }
294
266
  fn on_shutdown(&self, _: &temporal_sdk::Worker) {
295
- self.token.cancel()
267
+ if !self.cancel_on_workflow_completed {
268
+ self.token.cancel()
269
+ }
296
270
  }
297
271
  }
298
272
 
@@ -310,12 +284,9 @@ async fn cancel_after_act_starts(
310
284
  )]
311
285
  cancel_type: ActivityCancellationType,
312
286
  ) {
313
- let wf_name = format!(
314
- "cancel_after_act_starts_timer_{:?}_{:?}",
315
- cancel_on_backoff, cancel_type
316
- );
287
+ let wf_name = format!("cancel_after_act_starts_{cancel_on_backoff:?}_{cancel_type:?}");
317
288
  let mut starter = CoreWfStarter::new(&wf_name);
318
- starter.wft_timeout(Duration::from_secs(1));
289
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
319
290
  let mut worker = starter.worker().await;
320
291
  let bo_dur = cancel_on_backoff.unwrap_or_else(|| Duration::from_secs(1));
321
292
  worker.register_wf(&wf_name, move |ctx: WfContext| async move {
@@ -375,21 +346,17 @@ async fn cancel_after_act_starts(
375
346
  }
376
347
  });
377
348
 
378
- worker
379
- .submit_wf(
380
- wf_name.to_owned(),
381
- wf_name.to_owned(),
382
- vec![],
383
- WorkflowOptions::default(),
384
- )
385
- .await
386
- .unwrap();
349
+ starter.start_with_worker(&wf_name, &mut worker).await;
387
350
  worker
388
351
  .run_until_done_intercepted(Some(LACancellerInterceptor {
389
352
  token: manual_cancel,
353
+ // Only needed for this one case since the activity is not drained and prevents worker from shutting down.
354
+ cancel_on_workflow_completed: matches!(cancel_type, ActivityCancellationType::Abandon)
355
+ && cancel_on_backoff.is_none(),
390
356
  }))
391
357
  .await
392
358
  .unwrap();
359
+ starter.shutdown().await;
393
360
  }
394
361
 
395
362
  #[rstest::rstest]
@@ -408,6 +375,11 @@ async fn x_to_close_timeout(#[case] is_schedule: bool) {
408
375
  } else {
409
376
  (None, Some(Duration::from_secs(2)))
410
377
  };
378
+ let timeout_type = if is_schedule {
379
+ TimeoutType::ScheduleToClose
380
+ } else {
381
+ TimeoutType::StartToClose
382
+ };
411
383
 
412
384
  worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
413
385
  let res = ctx
@@ -427,7 +399,7 @@ async fn x_to_close_timeout(#[case] is_schedule: bool) {
427
399
  ..Default::default()
428
400
  })
429
401
  .await;
430
- assert!(res.timed_out());
402
+ assert_eq!(res.timed_out(), Some(timeout_type));
431
403
  Ok(().into())
432
404
  });
433
405
  worker.register_activity("echo", |ctx: ActContext, _: String| async move {
@@ -440,15 +412,7 @@ async fn x_to_close_timeout(#[case] is_schedule: bool) {
440
412
  Ok(())
441
413
  });
442
414
 
443
- worker
444
- .submit_wf(
445
- wf_name.to_owned(),
446
- wf_name.to_owned(),
447
- vec![],
448
- WorkflowOptions::default(),
449
- )
450
- .await
451
- .unwrap();
415
+ starter.start_with_worker(wf_name, &mut worker).await;
452
416
  worker.run_until_done().await.unwrap();
453
417
  }
454
418
 
@@ -472,43 +436,37 @@ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
472
436
  activity_type: "echo".to_string(),
473
437
  input: "hi".as_json_payload().expect("serializes fine"),
474
438
  retry_policy: RetryPolicy {
475
- initial_interval: Some(prost_dur!(from_micros(15))),
439
+ initial_interval: Some(prost_dur!(from_millis(15))),
476
440
  backoff_coefficient: 1_000.,
477
- maximum_interval: Some(prost_dur!(from_millis(1500))),
441
+ maximum_interval: Some(prost_dur!(from_millis(1000))),
478
442
  maximum_attempts: 40,
479
443
  non_retryable_error_types: vec![],
480
444
  },
481
- timer_backoff_threshold: Some(Duration::from_secs(1)),
482
- schedule_to_close_timeout: Some(Duration::from_secs(3)),
445
+ timer_backoff_threshold: Some(Duration::from_millis(500)),
446
+ schedule_to_close_timeout: Some(Duration::from_secs(2)),
483
447
  ..Default::default()
484
448
  })
485
449
  .await;
486
- assert!(res.timed_out());
450
+ assert_eq!(res.timed_out(), Some(TimeoutType::ScheduleToClose));
487
451
  Ok(().into())
488
452
  });
489
- worker.register_activity("echo", |_: ActContext, _: String| async {
453
+ let num_attempts: &'static _ = Box::leak(Box::new(AtomicU8::new(0)));
454
+ worker.register_activity("echo", move |_: ActContext, _: String| async {
455
+ num_attempts.fetch_add(1, Ordering::Relaxed);
490
456
  Result::<(), _>::Err(anyhow!("Oh no I failed!"))
491
457
  });
492
458
 
493
- worker
494
- .submit_wf(
495
- wf_name.to_owned(),
496
- wf_name.to_owned(),
497
- vec![],
498
- WorkflowOptions::default(),
499
- )
500
- .await
501
- .unwrap();
459
+ starter.start_with_worker(wf_name, &mut worker).await;
502
460
  worker.run_until_done().await.unwrap();
461
+ // 3 attempts b/c first backoff is very small, then the next 2 attempts take at least 2 seconds
462
+ // b/c of timer backoff.
463
+ assert_eq!(3, num_attempts.load(Ordering::Relaxed));
503
464
  }
504
465
 
505
466
  #[rstest::rstest]
506
467
  #[tokio::test]
507
468
  async fn eviction_wont_make_local_act_get_dropped(#[values(true, false)] short_wft_timeout: bool) {
508
- let wf_name = format!(
509
- "eviction_wont_make_local_act_get_dropped_{}",
510
- short_wft_timeout
511
- );
469
+ let wf_name = format!("eviction_wont_make_local_act_get_dropped_{short_wft_timeout}");
512
470
  let mut starter = CoreWfStarter::new(&wf_name);
513
471
  starter.max_cached_workflows(0);
514
472
  let mut worker = starter.worker().await;
@@ -574,15 +532,7 @@ async fn timer_backoff_concurrent_with_non_timer_backoff() {
574
532
  Result::<(), _>::Err(anyhow!("Oh no I failed!"))
575
533
  });
576
534
 
577
- worker
578
- .submit_wf(
579
- wf_name.to_owned(),
580
- wf_name.to_owned(),
581
- vec![],
582
- WorkflowOptions::default(),
583
- )
584
- .await
585
- .unwrap();
535
+ starter.start_with_worker(wf_name, &mut worker).await;
586
536
  worker.run_until_done().await.unwrap();
587
537
  }
588
538
 
@@ -613,7 +563,7 @@ async fn repro_nondeterminism_with_timer_bug() {
613
563
  _ = r1 => {
614
564
  t1.cancel(&ctx);
615
565
  },
616
- };
566
+ }
617
567
  ctx.timer(Duration::from_secs(1)).await;
618
568
  Ok(().into())
619
569
  });
@@ -638,85 +588,6 @@ async fn repro_nondeterminism_with_timer_bug() {
638
588
  .unwrap();
639
589
  }
640
590
 
641
- async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
642
- ctx.local_activity(LocalActivityOptions {
643
- activity_type: "delay".to_string(),
644
- input: "hi".as_json_payload().expect("serializes fine"),
645
- retry_policy: RetryPolicy {
646
- initial_interval: Some(prost_dur!(from_micros(15))),
647
- backoff_coefficient: 1_000.,
648
- maximum_interval: Some(prost_dur!(from_millis(1500))),
649
- maximum_attempts: 4,
650
- non_retryable_error_types: vec![],
651
- },
652
- timer_backoff_threshold: Some(Duration::from_secs(1)),
653
- ..Default::default()
654
- })
655
- .await;
656
- ctx.activity(ActivityOptions {
657
- activity_type: "delay".to_string(),
658
- start_to_close_timeout: Some(Duration::from_secs(20)),
659
- input: "hi!".as_json_payload().expect("serializes fine"),
660
- ..Default::default()
661
- })
662
- .await;
663
- Ok(().into())
664
- }
665
-
666
- // Expensive to run - worth enabling on a stress/regression pipeline.
667
- #[ignore]
668
- #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
669
- async fn evict_while_la_running_no_interference() {
670
- let wf_name = "evict_while_la_running_no_interference";
671
- let mut starter = CoreWfStarter::new(wf_name);
672
- starter.max_local_at(20);
673
- starter.max_cached_workflows(20);
674
- let mut worker = starter.worker().await;
675
-
676
- worker.register_wf(wf_name.to_owned(), la_problem_workflow);
677
- worker.register_activity("delay", |_: ActContext, _: String| async {
678
- tokio::time::sleep(Duration::from_secs(15)).await;
679
- Ok(())
680
- });
681
-
682
- let client = starter.get_client().await;
683
- let subfs = FuturesUnordered::new();
684
- for i in 1..100 {
685
- let wf_id = format!("{}-{}", wf_name, i);
686
- let run_id = worker
687
- .submit_wf(
688
- &wf_id,
689
- wf_name.to_owned(),
690
- vec![],
691
- WorkflowOptions::default(),
692
- )
693
- .await
694
- .unwrap();
695
- let cw = worker.core_worker.clone();
696
- let client = client.clone();
697
- subfs.push(async move {
698
- // Evict the workflow
699
- tokio::time::sleep(Duration::from_secs(1)).await;
700
- cw.request_workflow_eviction(&run_id);
701
- // Wake up workflow by sending signal
702
- client
703
- .signal_workflow_execution(
704
- wf_id,
705
- run_id.clone(),
706
- "whaatever".to_string(),
707
- None,
708
- None,
709
- )
710
- .await
711
- .unwrap();
712
- });
713
- }
714
- let runf = async {
715
- worker.run_until_done().await.unwrap();
716
- };
717
- tokio::join!(subfs.collect::<Vec<_>>(), runf);
718
- }
719
-
720
591
  #[rstest::rstest]
721
592
  #[tokio::test]
722
593
  async fn weird_la_nondeterminism_repro(#[values(true, false)] fix_hist: bool) {
@@ -758,7 +629,6 @@ async fn second_weird_la_nondeterminism_repro() {
758
629
  // Chop off uninteresting ending
759
630
  hist.events.truncate(24);
760
631
  let mut thb = TestHistoryBuilder::from_history(hist.events);
761
- // thb.add_workflow_task_completed();
762
632
  thb.add_workflow_execution_completed();
763
633
  hist = thb.get_full_history_info().unwrap().into();
764
634
 
@@ -773,3 +643,27 @@ async fn second_weird_la_nondeterminism_repro() {
773
643
  });
774
644
  worker.run().await.unwrap();
775
645
  }
646
+
647
+ #[tokio::test]
648
+ async fn third_weird_la_nondeterminism_repro() {
649
+ init_integ_telem();
650
+ let mut hist = history_from_proto_binary(
651
+ "histories/evict_while_la_running_no_interference-16_history.bin",
652
+ )
653
+ .await
654
+ .unwrap();
655
+ let mut thb = TestHistoryBuilder::from_history(hist.events);
656
+ thb.add_workflow_task_scheduled_and_started();
657
+ hist = thb.get_full_history_info().unwrap().into();
658
+
659
+ let mut worker = replay_sdk_worker([HistoryForReplay::new(hist, "fake".to_owned())]);
660
+ worker.register_wf(
661
+ "evict_while_la_running_no_interference",
662
+ la_problem_workflow,
663
+ );
664
+ worker.register_activity("delay", |_: ActContext, _: String| async {
665
+ tokio::time::sleep(Duration::from_secs(15)).await;
666
+ Ok(())
667
+ });
668
+ worker.run().await.unwrap();
669
+ }
@@ -20,6 +20,7 @@ async fn sends_modify_wf_props() {
20
20
  let wf_name = "can_upsert_memo";
21
21
  let wf_id = Uuid::new_v4();
22
22
  let mut starter = CoreWfStarter::new(wf_name);
23
+ starter.no_remote_activities();
23
24
  let mut worker = starter.worker().await;
24
25
 
25
26
  worker.register_wf(wf_name, memo_upserter);
@@ -43,10 +44,7 @@ async fn sends_modify_wf_props() {
43
44
  let catname = memo.get(FIELD_A).unwrap();
44
45
  let cuteness = memo.get(FIELD_B).unwrap();
45
46
  for payload in [catname, cuteness] {
46
- assert_eq!(
47
- &b"json/plain".to_vec(),
48
- payload.metadata.get("encoding").unwrap()
49
- );
47
+ assert!(payload.is_json_payload());
50
48
  }
51
49
  assert_eq!("enchi", String::from_json_payload(catname).unwrap());
52
50
  assert_eq!(9001, usize::from_json_payload(cuteness).unwrap());
@@ -2,7 +2,7 @@ use std::{
2
2
  sync::atomic::{AtomicBool, Ordering},
3
3
  time::Duration,
4
4
  };
5
- use temporal_client::WorkflowOptions;
5
+
6
6
  use temporal_sdk::{WfContext, WorkflowResult};
7
7
  use temporal_sdk_core_test_utils::CoreWfStarter;
8
8
 
@@ -27,18 +27,11 @@ pub async fn changes_wf(ctx: WfContext) -> WorkflowResult<()> {
27
27
  async fn writes_change_markers() {
28
28
  let wf_name = "writes_change_markers";
29
29
  let mut starter = CoreWfStarter::new(wf_name);
30
+ starter.no_remote_activities();
30
31
  let mut worker = starter.worker().await;
31
32
  worker.register_wf(wf_name.to_owned(), changes_wf);
32
33
 
33
- worker
34
- .submit_wf(
35
- wf_name.to_owned(),
36
- wf_name.to_owned(),
37
- vec![],
38
- WorkflowOptions::default(),
39
- )
40
- .await
41
- .unwrap();
34
+ starter.start_with_worker(wf_name, &mut worker).await;
42
35
  worker.run_until_done().await.unwrap();
43
36
  }
44
37
 
@@ -67,18 +60,11 @@ pub async fn no_change_then_change_wf(ctx: WfContext) -> WorkflowResult<()> {
67
60
  async fn can_add_change_markers() {
68
61
  let wf_name = "can_add_change_markers";
69
62
  let mut starter = CoreWfStarter::new(wf_name);
63
+ starter.no_remote_activities();
70
64
  let mut worker = starter.worker().await;
71
65
  worker.register_wf(wf_name.to_owned(), no_change_then_change_wf);
72
66
 
73
- worker
74
- .submit_wf(
75
- wf_name.to_owned(),
76
- wf_name.to_owned(),
77
- vec![],
78
- WorkflowOptions::default(),
79
- )
80
- .await
81
- .unwrap();
67
+ starter.start_with_worker(wf_name, &mut worker).await;
82
68
  worker.run_until_done().await.unwrap();
83
69
  }
84
70
 
@@ -97,17 +83,37 @@ pub async fn replay_with_change_marker_wf(ctx: WfContext) -> WorkflowResult<()>
97
83
  async fn replaying_with_patch_marker() {
98
84
  let wf_name = "replaying_with_patch_marker";
99
85
  let mut starter = CoreWfStarter::new(wf_name);
86
+ starter.no_remote_activities();
100
87
  let mut worker = starter.worker().await;
101
88
  worker.register_wf(wf_name.to_owned(), replay_with_change_marker_wf);
102
89
 
103
- worker
104
- .submit_wf(
105
- wf_name.to_owned(),
106
- wf_name.to_owned(),
107
- vec![],
108
- WorkflowOptions::default(),
109
- )
110
- .await
111
- .unwrap();
90
+ starter.start_with_worker(wf_name, &mut worker).await;
91
+ worker.run_until_done().await.unwrap();
92
+ }
93
+
94
+ /// Test that the internal patching mechanism works on the second workflow task when replaying.
95
+ /// Used as regression test for a bug that detected that we did not look ahead far enough to find
96
+ /// the next workflow task completion, which the flags are attached to.
97
+ #[tokio::test]
98
+ async fn patched_on_second_workflow_task_is_deterministic() {
99
+ let wf_name = "timer_patched_timer";
100
+ let mut starter = CoreWfStarter::new(wf_name);
101
+ // Disable caching to force replay from beginning
102
+ starter.max_cached_workflows(0).no_remote_activities();
103
+ let mut worker = starter.worker().await;
104
+ // Include a task failure as well to make sure that works
105
+ static FAIL_ONCE: AtomicBool = AtomicBool::new(true);
106
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
107
+ ctx.timer(Duration::from_millis(1)).await;
108
+ if FAIL_ONCE.load(Ordering::Acquire) {
109
+ FAIL_ONCE.store(false, Ordering::Release);
110
+ panic!("Enchi is hungry!");
111
+ }
112
+ assert!(ctx.patched(MY_PATCH_ID));
113
+ ctx.timer(Duration::from_millis(1)).await;
114
+ Ok(().into())
115
+ });
116
+
117
+ starter.start_with_worker(wf_name, &mut worker).await;
112
118
  worker.run_until_done().await.unwrap();
113
119
  }