@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
@@ -1,15 +1,17 @@
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,
9
9
  };
10
10
  use temporal_sdk_core_test_utils::{
11
- get_integ_server_options, CoreWfStarter, WorkerTestHelpers, NAMESPACE,
11
+ drain_pollers_and_shutdown, get_integ_server_options, CoreWfStarter, WorkerTestHelpers,
12
+ NAMESPACE,
12
13
  };
14
+ use tokio::time::sleep;
13
15
 
14
16
  #[tokio::test]
15
17
  async fn client_list_open_closed_workflow_executions() {
@@ -22,9 +24,7 @@ async fn client_list_open_closed_workflow_executions() {
22
24
  let latest = earliest + Duration::from_secs(60);
23
25
 
24
26
  // start workflow
25
- let run_id = starter
26
- .start_wf_with_id(wf_name.to_owned(), WorkflowOptions::default())
27
- .await;
27
+ let run_id = starter.start_wf_with_id(wf_name.to_owned()).await;
28
28
  let task = core.poll_workflow_activation().await.unwrap();
29
29
  assert_matches!(
30
30
  task.jobs.as_slice(),
@@ -52,28 +52,86 @@ async fn client_list_open_closed_workflow_executions() {
52
52
 
53
53
  // Complete workflow
54
54
  core.complete_execution(&task.run_id).await;
55
+ drain_pollers_and_shutdown(&core).await;
55
56
 
56
- // List above CLOSED workflow
57
- let start_time_filter = StartTimeFilter {
58
- earliest_time: Some(earliest).and_then(|t| t.try_into().ok()),
59
- latest_time: Some(latest).and_then(|t| t.try_into().ok()),
60
- };
61
- let filter = ListClosedFilters::ExecutionFilter(WorkflowExecutionFilter {
62
- workflow_id: wf_name.clone(),
63
- run_id,
64
- });
65
- let closed_workflows = client
66
- .list_closed_workflow_executions(
67
- 1,
68
- Default::default(),
69
- Some(start_time_filter),
70
- Some(filter),
71
- )
57
+ // List above CLOSED workflow. Visibility doesn't always update immediately so we give this a
58
+ // few tries.
59
+ let mut passed = false;
60
+ for _ in 1..=5 {
61
+ let closed_workflows = client
62
+ .list_closed_workflow_executions(
63
+ 1,
64
+ Default::default(),
65
+ Some(StartTimeFilter {
66
+ earliest_time: Some(earliest).and_then(|t| t.try_into().ok()),
67
+ latest_time: Some(latest).and_then(|t| t.try_into().ok()),
68
+ }),
69
+ Some(ListClosedFilters::ExecutionFilter(
70
+ WorkflowExecutionFilter {
71
+ workflow_id: wf_name.clone(),
72
+ run_id: run_id.clone(),
73
+ },
74
+ )),
75
+ )
76
+ .await
77
+ .unwrap();
78
+ if closed_workflows.executions.len() == 1 {
79
+ let workflow = &closed_workflows.executions[0];
80
+ if workflow.execution.as_ref().unwrap().workflow_id == wf_name {
81
+ passed = true;
82
+ break;
83
+ }
84
+ }
85
+ sleep(Duration::from_millis(100)).await;
86
+ }
87
+ assert!(passed);
88
+ }
89
+
90
+ #[tokio::test]
91
+ async fn client_create_namespace() {
92
+ let client = Arc::new(
93
+ get_integ_server_options()
94
+ .connect(NAMESPACE.to_owned(), None, None)
95
+ .await
96
+ .expect("Must connect"),
97
+ );
98
+
99
+ let register_options = RegisterNamespaceOptions::builder()
100
+ .namespace("test-create-namespace")
101
+ .description("it's alive")
102
+ .build()
103
+ .unwrap();
104
+
105
+ client
106
+ .register_namespace(register_options.clone())
72
107
  .await
73
108
  .unwrap();
74
- assert_eq!(closed_workflows.executions.len(), 1);
75
- let workflow = closed_workflows.executions[0].clone();
76
- assert_eq!(workflow.execution.as_ref().unwrap().workflow_id, wf_name);
109
+
110
+ //#Hack, not sure how else to wait for a proper response. RegisterNamespace isn't safe to read
111
+ //after write
112
+ let mut attempts = 0;
113
+ let wait_time = Duration::from_secs(1);
114
+ loop {
115
+ attempts += 1;
116
+ let resp = client
117
+ .describe_namespace(Namespace::Name(register_options.namespace.clone()))
118
+ .await;
119
+
120
+ match resp {
121
+ Ok(n) => {
122
+ let namespace_info = n.namespace_info.unwrap();
123
+ assert_eq!(namespace_info.name, register_options.namespace);
124
+ assert_eq!(namespace_info.description, register_options.description);
125
+ return;
126
+ }
127
+ _ => {
128
+ if attempts == 12 {
129
+ panic!("failed to query registered namespace");
130
+ }
131
+ sleep(wait_time).await
132
+ }
133
+ }
134
+ }
77
135
  }
78
136
 
79
137
  #[tokio::test]
@@ -1,8 +1,11 @@
1
+ use anyhow::anyhow;
1
2
  use assert_matches::assert_matches;
3
+ use futures_util::future::join_all;
2
4
  use std::time::Duration;
3
5
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
4
6
  use temporal_sdk::{
5
- ActContext, ActExitValue, ActivityOptions, CancellableFuture, WfContext, WorkflowResult,
7
+ ActContext, ActExitValue, ActivityCancelledError, ActivityOptions, CancellableFuture,
8
+ WfContext, WorkflowResult,
6
9
  };
7
10
  use temporal_sdk_core_protos::{
8
11
  coresdk::{
@@ -19,16 +22,17 @@ use temporal_sdk_core_protos::{
19
22
  IntoCompletion,
20
23
  },
21
24
  temporal::api::{
22
- common::v1::{ActivityType, Payload, Payloads},
25
+ common::v1::{ActivityType, Payload, Payloads, RetryPolicy},
23
26
  enums::v1::RetryState,
24
27
  failure::v1::{failure::FailureInfo, ActivityFailureInfo, Failure},
25
28
  },
26
- TaskToken,
29
+ TaskToken, DEFAULT_ACTIVITY_TYPE,
27
30
  };
28
31
  use temporal_sdk_core_test_utils::{
29
- init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
32
+ drain_pollers_and_shutdown, init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter,
33
+ WorkerTestHelpers,
30
34
  };
31
- use tokio::time::sleep;
35
+ use tokio::{join, sync::Semaphore, time::sleep};
32
36
 
33
37
  pub async fn one_activity_wf(ctx: WfContext) -> WorkflowResult<()> {
34
38
  ctx.activity(ActivityOptions {
@@ -97,7 +101,7 @@ async fn activity_workflow() {
97
101
  assert_matches!(
98
102
  task.variant,
99
103
  Some(act_task::Variant::Start(start_activity)) => {
100
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
104
+ assert_eq!(start_activity.activity_type, DEFAULT_ACTIVITY_TYPE.to_string())
101
105
  }
102
106
  );
103
107
  let response_payload = Payload {
@@ -154,16 +158,78 @@ async fn activity_non_retryable_failure() {
154
158
  )
155
159
  .await
156
160
  .unwrap();
157
- // Poll activity and verify that it's been scheduled with correct parameters
161
+ // Poll activity and verify that it's been scheduled
158
162
  let task = core.poll_activity_task().await.unwrap();
163
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
164
+ // Fail activity with non-retryable error
165
+ let failure = Failure::application_failure("activity failed".to_string(), true);
166
+ core.complete_activity_task(ActivityTaskCompletion {
167
+ task_token: task.task_token,
168
+ result: Some(ActivityExecutionResult::fail(failure.clone())),
169
+ })
170
+ .await
171
+ .unwrap();
172
+ // Poll workflow task and verify that activity has failed.
173
+ let task = core.poll_workflow_activation().await.unwrap();
159
174
  assert_matches!(
160
- task.variant,
161
- Some(act_task::Variant::Start(start_activity)) => {
162
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
175
+ task.jobs.as_slice(),
176
+ [
177
+ WorkflowActivationJob {
178
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(
179
+ ResolveActivity {seq, result: Some(ActivityResolution{
180
+ status: Some(act_res::Status::Failed(activity_result::Failure{
181
+ failure: Some(f),
182
+ }))})}
183
+ )),
184
+ },
185
+ ] => {
186
+ assert_eq!(*seq, 0);
187
+ assert_eq!(f, &Failure{
188
+ message: "Activity task failed".to_owned(),
189
+ cause: Some(Box::new(failure)),
190
+ failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
191
+ activity_id: "act-1".to_owned(),
192
+ activity_type: Some(ActivityType {
193
+ name: DEFAULT_ACTIVITY_TYPE.to_owned(),
194
+ }),
195
+ scheduled_event_id: 5,
196
+ started_event_id: 6,
197
+ identity: "integ_tester".to_owned(),
198
+ retry_state: RetryState::NonRetryableFailure as i32,
199
+ })),
200
+ ..Default::default()
201
+ });
163
202
  }
164
203
  );
204
+ core.complete_execution(&task.run_id).await;
205
+ }
206
+
207
+ #[tokio::test]
208
+ async fn activity_non_retryable_failure_with_error() {
209
+ let mut starter = init_core_and_create_wf("activity_non_retryable_failure").await;
210
+ let core = starter.get_worker().await;
211
+ let task_q = starter.get_task_queue();
212
+ let activity_id = "act-1";
213
+ let task = core.poll_workflow_activation().await.unwrap();
214
+ // Complete workflow task and schedule activity
215
+ core.complete_workflow_activation(
216
+ schedule_activity_cmd(
217
+ 0,
218
+ task_q,
219
+ activity_id,
220
+ ActivityCancellationType::TryCancel,
221
+ Duration::from_secs(60),
222
+ Duration::from_secs(60),
223
+ )
224
+ .into_completion(task.run_id),
225
+ )
226
+ .await
227
+ .unwrap();
228
+ // Poll activity and verify that it's been scheduled
229
+ let task = core.poll_activity_task().await.unwrap();
230
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
165
231
  // Fail activity with non-retryable error
166
- let failure = Failure::application_failure("activity failed".to_string(), true);
232
+ let failure = Failure::application_failure_from_error(anyhow!("activity failed"), true);
167
233
  core.complete_activity_task(ActivityTaskCompletion {
168
234
  task_token: task.task_token,
169
235
  result: Some(ActivityExecutionResult::fail(failure.clone())),
@@ -191,7 +257,7 @@ async fn activity_non_retryable_failure() {
191
257
  failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
192
258
  activity_id: "act-1".to_owned(),
193
259
  activity_type: Some(ActivityType {
194
- name: "test_activity".to_owned(),
260
+ name: DEFAULT_ACTIVITY_TYPE.to_owned(),
195
261
  }),
196
262
  scheduled_event_id: 5,
197
263
  started_event_id: 6,
@@ -228,12 +294,7 @@ async fn activity_retry() {
228
294
  .unwrap();
229
295
  // Poll activity 1st time
230
296
  let task = core.poll_activity_task().await.unwrap();
231
- assert_matches!(
232
- task.variant,
233
- Some(act_task::Variant::Start(start_activity)) => {
234
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
235
- }
236
- );
297
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
237
298
  // Fail activity with retryable error
238
299
  let failure = Failure::application_failure("activity failed".to_string(), false);
239
300
  core.complete_activity_task(ActivityTaskCompletion {
@@ -244,12 +305,7 @@ async fn activity_retry() {
244
305
  .unwrap();
245
306
  // Poll 2nd time
246
307
  let task = core.poll_activity_task().await.unwrap();
247
- assert_matches!(
248
- task.variant,
249
- Some(act_task::Variant::Start(start_activity)) => {
250
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
251
- }
252
- );
308
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
253
309
  // Complete activity successfully
254
310
  let response_payload = Payload {
255
311
  data: b"hello ".to_vec(),
@@ -308,15 +364,10 @@ async fn activity_cancellation_try_cancel() {
308
364
  )
309
365
  .await
310
366
  .unwrap();
311
- // Poll activity and verify that it's been scheduled with correct parameters, we don't expect to
312
- // complete it in this test as activity is try-cancelled.
367
+ // Poll activity and verify that it's been scheduled, we don't expect to complete it in this
368
+ // test as activity is try-cancelled.
313
369
  let activity_task = core.poll_activity_task().await.unwrap();
314
- assert_matches!(
315
- activity_task.variant,
316
- Some(act_task::Variant::Start(start_activity)) => {
317
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
318
- }
319
- );
370
+ assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
320
371
  // Poll workflow task and verify that activity has failed.
321
372
  let task = core.poll_workflow_activation().await.unwrap();
322
373
  assert_matches!(
@@ -453,15 +504,10 @@ async fn started_activity_timeout() {
453
504
  )
454
505
  .await
455
506
  .unwrap();
456
- // Poll activity and verify that it's been scheduled with correct parameters, we don't expect to
457
- // complete it in this test as activity is timed out after 1 second.
507
+ // Poll activity and verify that it's been scheduled, we don't expect to complete it in this
508
+ // test as activity is timed out after 1 second.
458
509
  let activity_task = core.poll_activity_task().await.unwrap();
459
- assert_matches!(
460
- activity_task.variant,
461
- Some(act_task::Variant::Start(start_activity)) => {
462
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
463
- }
464
- );
510
+ assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
465
511
  let task = core.poll_workflow_activation().await.unwrap();
466
512
  assert_matches!(
467
513
  task.jobs.as_slice(),
@@ -517,15 +563,10 @@ async fn activity_cancellation_wait_cancellation_completed() {
517
563
  )
518
564
  .await
519
565
  .unwrap();
520
- // Poll activity and verify that it's been scheduled with correct parameters, we don't expect to
521
- // complete it in this test as activity is wait-cancelled.
566
+ // Poll activity and verify that it's been scheduled, we don't expect to complete it in this
567
+ // test as activity is wait-cancelled.
522
568
  let activity_task = core.poll_activity_task().await.unwrap();
523
- assert_matches!(
524
- activity_task.variant,
525
- Some(act_task::Variant::Start(start_activity)) => {
526
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
527
- }
528
- );
569
+ assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
529
570
  // Poll workflow task and verify that activity has failed.
530
571
  let task = core.poll_workflow_activation().await.unwrap();
531
572
  assert_matches!(
@@ -584,15 +625,10 @@ async fn activity_cancellation_abandon() {
584
625
  )
585
626
  .await
586
627
  .unwrap();
587
- // Poll activity and verify that it's been scheduled with correct parameters, we don't expect to
588
- // complete it in this test as activity is abandoned.
628
+ // Poll activity and verify that it's been scheduled, we don't expect to complete it in this
629
+ // test as activity is abandoned.
589
630
  let activity_task = core.poll_activity_task().await.unwrap();
590
- assert_matches!(
591
- activity_task.variant,
592
- Some(act_task::Variant::Start(start_activity)) => {
593
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
594
- }
595
- );
631
+ assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
596
632
  // Poll workflow task and verify that activity has failed.
597
633
  let task = core.poll_workflow_activation().await.unwrap();
598
634
  assert_matches!(
@@ -640,14 +676,9 @@ async fn async_activity_completion_workflow() {
640
676
  )
641
677
  .await
642
678
  .unwrap();
643
- // Poll activity and verify that it's been scheduled with correct parameters
679
+ // Poll activity and verify that it's been scheduled
644
680
  let task = core.poll_activity_task().await.unwrap();
645
- assert_matches!(
646
- task.variant,
647
- Some(act_task::Variant::Start(start_activity)) => {
648
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
649
- }
650
- );
681
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
651
682
  let response_payload = Payload {
652
683
  data: b"hello ".to_vec(),
653
684
  metadata: Default::default(),
@@ -712,14 +743,9 @@ async fn activity_cancelled_after_heartbeat_times_out() {
712
743
  )
713
744
  .await
714
745
  .unwrap();
715
- // Poll activity and verify that it's been scheduled with correct parameters
746
+ // Poll activity and verify that it's been scheduled
716
747
  let task = core.poll_activity_task().await.unwrap();
717
- assert_matches!(
718
- task.variant,
719
- Some(act_task::Variant::Start(start_activity)) => {
720
- assert_eq!(start_activity.activity_type, "test_activity".to_string())
721
- }
722
- );
748
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
723
749
  // Delay the heartbeat
724
750
  sleep(Duration::from_secs(2)).await;
725
751
  core.record_activity_heartbeat(ActivityHeartbeat {
@@ -741,7 +767,7 @@ async fn activity_cancelled_after_heartbeat_times_out() {
741
767
  .unwrap();
742
768
 
743
769
  // Verify shutdown completes
744
- core.shutdown().await;
770
+ drain_pollers_and_shutdown(&core).await;
745
771
  // Cleanup just in case
746
772
  starter
747
773
  .get_client()
@@ -822,7 +848,7 @@ async fn it_can_complete_async() {
822
848
  Some(act_res::Status::Completed(activity_result::Success { result })) => result
823
849
  .map(|p| String::from_json_payload(&p).unwrap())
824
850
  .unwrap(),
825
- _ => panic!("activity task failed {:?}", activity_resolution),
851
+ _ => panic!("activity task failed {activity_resolution:?}"),
826
852
  };
827
853
 
828
854
  assert_eq!(&res, async_response);
@@ -876,3 +902,66 @@ async fn it_can_complete_async() {
876
902
 
877
903
  worker.run_until_done().await.unwrap();
878
904
  }
905
+
906
+ #[tokio::test]
907
+ async fn graceful_shutdown() {
908
+ let wf_name = "graceful_shutdown";
909
+ let mut starter = CoreWfStarter::new(wf_name);
910
+ starter.worker_config.graceful_shutdown_period = Some(Duration::from_millis(500));
911
+ let mut worker = starter.worker().await;
912
+ let client = starter.get_client().await;
913
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
914
+ let act_futs = (1..=10).map(|_| {
915
+ ctx.activity(ActivityOptions {
916
+ activity_type: "sleeper".to_string(),
917
+ start_to_close_timeout: Some(Duration::from_secs(5)),
918
+ retry_policy: Some(RetryPolicy {
919
+ maximum_attempts: 1,
920
+ ..Default::default()
921
+ }),
922
+ cancellation_type: ActivityCancellationType::WaitCancellationCompleted,
923
+ input: "hi".as_json_payload().unwrap(),
924
+ ..Default::default()
925
+ })
926
+ });
927
+ join_all(act_futs).await;
928
+ Ok(().into())
929
+ });
930
+ static ACTS_STARTED: Semaphore = Semaphore::const_new(0);
931
+ static ACTS_DONE: Semaphore = Semaphore::const_new(0);
932
+ worker.register_activity("sleeper", |ctx: ActContext, _: String| async move {
933
+ ACTS_STARTED.add_permits(1);
934
+ // just wait to be cancelled
935
+ ctx.cancelled().await;
936
+ ACTS_DONE.add_permits(1);
937
+ Result::<(), _>::Err(ActivityCancelledError::default().into())
938
+ });
939
+
940
+ worker
941
+ .submit_wf(
942
+ wf_name.to_owned(),
943
+ wf_name.to_owned(),
944
+ vec![],
945
+ WorkflowOptions::default(),
946
+ )
947
+ .await
948
+ .unwrap();
949
+
950
+ let handle = worker.inner_mut().shutdown_handle();
951
+ let shutdowner = async {
952
+ // Wait for all acts to be started before initiating shutdown
953
+ let _ = ACTS_STARTED.acquire_many(10).await;
954
+ handle();
955
+ // Kill workflow once all acts are cancelled. This also ensures we actually see all the
956
+ // cancels, otherwise run_until_done will hang since the workflow won't complete.
957
+ let _ = ACTS_DONE.acquire_many(10).await;
958
+ client
959
+ .terminate_workflow_execution(wf_name.to_owned(), None)
960
+ .await
961
+ .unwrap();
962
+ };
963
+ let runner = async {
964
+ worker.run_until_done().await.unwrap();
965
+ };
966
+ join!(shutdowner, runner);
967
+ }
@@ -33,6 +33,7 @@ async fn cancel_receiver(mut ctx: WfContext) -> WorkflowResult<()> {
33
33
  #[tokio::test]
34
34
  async fn sends_cancel_to_other_wf() {
35
35
  let mut starter = CoreWfStarter::new("sends_cancel_to_other_wf");
36
+ starter.no_remote_activities();
36
37
  let mut worker = starter.worker().await;
37
38
  worker.register_wf("sender", cancel_sender);
38
39
  worker.register_wf("receiver", cancel_receiver);
@@ -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;
@@ -21,25 +21,18 @@ async fn cancelled_wf(mut ctx: WfContext) -> WorkflowResult<()> {
21
21
  async fn cancel_during_timer() {
22
22
  let wf_name = "cancel_during_timer";
23
23
  let mut starter = CoreWfStarter::new(wf_name);
24
+ starter.no_remote_activities();
24
25
  let mut worker = starter.worker().await;
25
26
  let client = starter.get_client().await;
26
27
  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();
28
+ starter.start_with_worker(wf_name, &mut worker).await;
29
+ let wf_id = starter.get_task_queue().to_string();
37
30
 
38
31
  let canceller = async {
39
32
  tokio::time::sleep(Duration::from_millis(500)).await;
40
33
  // Cancel the workflow externally
41
34
  client
42
- .cancel_workflow_execution(wf_name.to_string(), None, "Dieee".to_string(), None)
35
+ .cancel_workflow_execution(wf_id.clone(), None, "Dieee".to_string(), None)
43
36
  .await
44
37
  .unwrap();
45
38
  };
@@ -47,7 +40,7 @@ async fn cancel_during_timer() {
47
40
  let (_, res) = tokio::join!(canceller, worker.run_until_done());
48
41
  res.unwrap();
49
42
  let desc = client
50
- .describe_workflow_execution(wf_name.to_string(), None)
43
+ .describe_workflow_execution(wf_id, None)
51
44
  .await
52
45
  .unwrap();
53
46
 
@@ -1,8 +1,13 @@
1
1
  use anyhow::anyhow;
2
- use temporal_client::WorkflowOptions;
3
- use temporal_sdk::{ChildWorkflowOptions, WfContext, WorkflowResult};
4
- use temporal_sdk_core_protos::coresdk::child_workflow::{child_workflow_result, Success};
2
+ use std::time::Duration;
3
+ use temporal_client::{WorkflowClientTrait, WorkflowOptions};
4
+ use temporal_sdk::{ChildWorkflowOptions, WfContext, WfExitValue, WorkflowResult};
5
+ use temporal_sdk_core_protos::{
6
+ coresdk::child_workflow::{child_workflow_result, ChildWorkflowCancellationType, Success},
7
+ temporal::api::enums::v1::ParentClosePolicy,
8
+ };
5
9
  use temporal_sdk_core_test_utils::CoreWfStarter;
10
+ use tokio::sync::Barrier;
6
11
 
7
12
  static PARENT_WF_TYPE: &str = "parent_wf";
8
13
  static CHILD_WF_TYPE: &str = "child_wf";
@@ -32,6 +37,7 @@ async fn parent_wf(ctx: WfContext) -> WorkflowResult<()> {
32
37
  #[tokio::test]
33
38
  async fn child_workflow_happy_path() {
34
39
  let mut starter = CoreWfStarter::new("child-workflows");
40
+ starter.no_remote_activities();
35
41
  let mut worker = starter.worker().await;
36
42
 
37
43
  worker.register_wf(PARENT_WF_TYPE.to_string(), parent_wf);
@@ -48,3 +54,74 @@ async fn child_workflow_happy_path() {
48
54
  .unwrap();
49
55
  worker.run_until_done().await.unwrap();
50
56
  }
57
+
58
+ #[tokio::test]
59
+ async fn abandoned_child_bug_repro() {
60
+ let mut starter = CoreWfStarter::new("child-workflow-abandon-bug");
61
+ starter.no_remote_activities();
62
+ let mut worker = starter.worker().await;
63
+ let barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
64
+
65
+ worker.register_wf(
66
+ PARENT_WF_TYPE.to_string(),
67
+ move |mut ctx: WfContext| async move {
68
+ let child = ctx.child_workflow(ChildWorkflowOptions {
69
+ workflow_id: "abandoned-child".to_owned(),
70
+ workflow_type: CHILD_WF_TYPE.to_owned(),
71
+ parent_close_policy: ParentClosePolicy::Abandon,
72
+ cancel_type: ChildWorkflowCancellationType::Abandon,
73
+ ..Default::default()
74
+ });
75
+
76
+ let started = child
77
+ .start(&ctx)
78
+ .await
79
+ .into_started()
80
+ .expect("Child chould start OK");
81
+ barr.wait().await;
82
+ // Wait for cancel signal
83
+ ctx.cancelled().await;
84
+ // Cancel the child immediately
85
+ started.cancel(&ctx);
86
+ // Need to do something else, so we'll see the ChildWorkflowExecutionCanceled event
87
+ ctx.timer(Duration::from_secs(1)).await;
88
+ started.result().await;
89
+ Ok(().into())
90
+ },
91
+ );
92
+ worker.register_wf(CHILD_WF_TYPE.to_string(), |mut ctx: WfContext| async move {
93
+ ctx.cancelled().await;
94
+ Ok(WfExitValue::Cancelled)
95
+ });
96
+
97
+ worker
98
+ .submit_wf(
99
+ "parent-abandoner".to_string(),
100
+ PARENT_WF_TYPE.to_owned(),
101
+ vec![],
102
+ WorkflowOptions::default(),
103
+ )
104
+ .await
105
+ .unwrap();
106
+ let client = starter.get_client().await;
107
+ let canceller = async {
108
+ barr.wait().await;
109
+ client
110
+ .cancel_workflow_execution(
111
+ "parent-abandoner".to_string(),
112
+ None,
113
+ "die".to_string(),
114
+ None,
115
+ )
116
+ .await
117
+ .unwrap();
118
+ client
119
+ .cancel_workflow_execution("abandoned-child".to_string(), None, "die".to_string(), None)
120
+ .await
121
+ .unwrap();
122
+ };
123
+ let runner = async move {
124
+ worker.run_until_done().await.unwrap();
125
+ };
126
+ tokio::join!(canceller, runner);
127
+ }
@@ -21,6 +21,7 @@ async fn continue_as_new_wf(ctx: WfContext) -> WorkflowResult<()> {
21
21
  async fn continue_as_new_happy_path() {
22
22
  let wf_name = "continue_as_new_happy_path";
23
23
  let mut starter = CoreWfStarter::new(wf_name);
24
+ starter.no_remote_activities();
24
25
  let mut worker = starter.worker().await;
25
26
  worker.register_wf(wf_name.to_string(), continue_as_new_wf);
26
27
 
@@ -40,11 +41,14 @@ async fn continue_as_new_happy_path() {
40
41
  async fn continue_as_new_multiple_concurrent() {
41
42
  let wf_name = "continue_as_new_multiple_concurrent";
42
43
  let mut starter = CoreWfStarter::new(wf_name);
43
- starter.max_cached_workflows(3).max_wft(3);
44
+ starter
45
+ .no_remote_activities()
46
+ .max_cached_workflows(3)
47
+ .max_wft(3);
44
48
  let mut worker = starter.worker().await;
45
49
  worker.register_wf(wf_name.to_string(), continue_as_new_wf);
46
50
 
47
- let wf_names = (1..=20).map(|i| format!("{}-{}", wf_name, i));
51
+ let wf_names = (1..=20).map(|i| format!("{wf_name}-{i}"));
48
52
  for name in wf_names.clone() {
49
53
  worker
50
54
  .submit_wf(