@temporalio/core-bridge 1.13.0 → 1.13.2

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 (181) hide show
  1. package/Cargo.lock +239 -382
  2. package/Cargo.toml +11 -11
  3. package/lib/native.d.ts +10 -3
  4. package/package.json +3 -3
  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/.cargo/config.toml +71 -11
  11. package/sdk-core/.clippy.toml +1 -0
  12. package/sdk-core/.github/workflows/heavy.yml +2 -0
  13. package/sdk-core/.github/workflows/per-pr.yml +50 -18
  14. package/sdk-core/ARCHITECTURE.md +44 -48
  15. package/sdk-core/Cargo.toml +26 -7
  16. package/sdk-core/README.md +4 -0
  17. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  18. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  19. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  20. package/sdk-core/client/Cargo.toml +8 -7
  21. package/sdk-core/client/src/callback_based.rs +1 -2
  22. package/sdk-core/client/src/lib.rs +485 -299
  23. package/sdk-core/client/src/metrics.rs +32 -8
  24. package/sdk-core/client/src/proxy.rs +124 -5
  25. package/sdk-core/client/src/raw.rs +598 -307
  26. package/sdk-core/client/src/replaceable.rs +253 -0
  27. package/sdk-core/client/src/retry.rs +9 -6
  28. package/sdk-core/client/src/worker_registry/mod.rs +19 -3
  29. package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
  30. package/sdk-core/core/Cargo.toml +100 -31
  31. package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
  32. package/sdk-core/core/src/core_tests/mod.rs +2 -8
  33. package/sdk-core/core/src/core_tests/queries.rs +3 -5
  34. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
  35. package/sdk-core/core/src/core_tests/updates.rs +4 -5
  36. package/sdk-core/core/src/core_tests/workers.rs +4 -3
  37. package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
  38. package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
  39. package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
  40. package/sdk-core/core/src/internal_flags.rs +11 -1
  41. package/sdk-core/core/src/lib.rs +50 -36
  42. package/sdk-core/core/src/pollers/mod.rs +5 -5
  43. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  44. package/sdk-core/core/src/protosext/mod.rs +13 -5
  45. package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
  46. package/sdk-core/core/src/retry_logic.rs +256 -108
  47. package/sdk-core/core/src/telemetry/metrics.rs +1 -0
  48. package/sdk-core/core/src/telemetry/mod.rs +8 -2
  49. package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
  50. package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
  51. package/sdk-core/core/src/test_help/mod.rs +10 -1100
  52. package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
  53. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
  55. package/sdk-core/core/src/worker/activities.rs +10 -3
  56. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  57. package/sdk-core/core/src/worker/client.rs +130 -93
  58. package/sdk-core/core/src/worker/heartbeat.rs +12 -13
  59. package/sdk-core/core/src/worker/mod.rs +31 -21
  60. package/sdk-core/core/src/worker/nexus.rs +14 -3
  61. package/sdk-core/core/src/worker/slot_provider.rs +9 -0
  62. package/sdk-core/core/src/worker/tuner.rs +159 -0
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
  64. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
  65. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
  66. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
  67. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
  68. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
  69. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
  71. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
  72. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
  73. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
  74. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
  75. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
  76. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
  77. package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
  78. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
  79. package/sdk-core/core-api/Cargo.toml +4 -4
  80. package/sdk-core/core-api/src/envconfig.rs +153 -54
  81. package/sdk-core/core-api/src/lib.rs +68 -0
  82. package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
  83. package/sdk-core/core-api/src/telemetry.rs +13 -0
  84. package/sdk-core/core-c-bridge/Cargo.toml +13 -8
  85. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
  86. package/sdk-core/core-c-bridge/src/client.rs +462 -184
  87. package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
  88. package/sdk-core/core-c-bridge/src/lib.rs +1 -0
  89. package/sdk-core/core-c-bridge/src/random.rs +4 -4
  90. package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
  91. package/sdk-core/core-c-bridge/src/testing.rs +1 -4
  92. package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
  93. package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
  94. package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
  95. package/sdk-core/core-c-bridge/src/worker.rs +319 -66
  96. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
  98. package/sdk-core/sdk/Cargo.toml +8 -2
  99. package/sdk-core/sdk/src/activity_context.rs +1 -1
  100. package/sdk-core/sdk/src/app_data.rs +1 -1
  101. package/sdk-core/sdk/src/interceptors.rs +1 -4
  102. package/sdk-core/sdk/src/lib.rs +1 -5
  103. package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
  104. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  105. package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
  106. package/sdk-core/sdk-core-protos/build.rs +10 -23
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  116. package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
  117. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
  118. package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
  119. package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
  120. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
  121. package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  122. package/sdk-core/tests/cloud_tests.rs +10 -8
  123. package/sdk-core/tests/common/http_proxy.rs +134 -0
  124. package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
  125. package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
  126. package/sdk-core/tests/fuzzy_workflow.rs +1 -1
  127. package/sdk-core/tests/global_metric_tests.rs +8 -7
  128. package/sdk-core/tests/heavy_tests.rs +7 -3
  129. package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
  130. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
  131. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
  132. package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
  133. package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  134. package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
  135. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  136. package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
  137. package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
  138. package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
  139. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
  140. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
  141. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
  144. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
  145. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
  146. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
  147. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  148. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
  149. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
  150. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
  151. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
  152. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
  153. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
  154. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
  155. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
  156. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
  157. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
  158. package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
  159. package/sdk-core/tests/main.rs +26 -17
  160. package/sdk-core/tests/manual_tests.rs +5 -1
  161. package/sdk-core/tests/runner.rs +22 -40
  162. package/sdk-core/tests/shared_tests/mod.rs +1 -1
  163. package/sdk-core/tests/shared_tests/priority.rs +1 -1
  164. package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
  165. package/src/client.rs +97 -20
  166. package/src/helpers/callbacks.rs +4 -4
  167. package/src/helpers/errors.rs +7 -1
  168. package/src/helpers/handles.rs +1 -0
  169. package/src/helpers/try_from_js.rs +4 -3
  170. package/src/lib.rs +3 -2
  171. package/src/metrics.rs +3 -0
  172. package/src/runtime.rs +5 -2
  173. package/src/worker.rs +9 -12
  174. package/ts/native.ts +13 -3
  175. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  176. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  177. package/sdk-core/core/src/core_tests/determinism.rs +0 -318
  178. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  179. package/sdk-core/test-utils/Cargo.toml +0 -38
  180. package/sdk-core/test-utils/src/histfetch.rs +0 -28
  181. package/sdk-core/test-utils/src/interceptors.rs +0 -46
@@ -1,7 +1,11 @@
1
- use crate::integ_tests::activity_functions::echo;
1
+ use crate::{
2
+ common::{CoreWfStarter, eventually},
3
+ integ_tests::activity_functions::echo,
4
+ };
2
5
  use std::time::Duration;
3
6
  use temporal_client::{NamespacedClient, WorkflowOptions, WorkflowService};
4
7
  use temporal_sdk::{ActivityOptions, WfContext};
8
+ use temporal_sdk_core::test_help::WorkerTestHelpers;
5
9
  use temporal_sdk_core_api::worker::{
6
10
  WorkerDeploymentOptions, WorkerDeploymentVersion, WorkerVersioningStrategy,
7
11
  };
@@ -18,8 +22,8 @@ use temporal_sdk_core_protos::{
18
22
  },
19
23
  },
20
24
  };
21
- use temporal_sdk_core_test_utils::{CoreWfStarter, WorkerTestHelpers, eventually};
22
25
  use tokio::join;
26
+ use tonic::IntoRequest;
23
27
 
24
28
  #[rstest::rstest]
25
29
  #[tokio::test]
@@ -73,10 +77,13 @@ async fn sets_deployment_info_on_task_responses(#[values(true, false)] use_defau
73
77
  client
74
78
  .get_client()
75
79
  .clone()
76
- .describe_worker_deployment(DescribeWorkerDeploymentRequest {
77
- namespace: client.namespace().to_string(),
78
- deployment_name: deploy_name.clone(),
79
- })
80
+ .describe_worker_deployment(
81
+ DescribeWorkerDeploymentRequest {
82
+ namespace: client.namespace(),
83
+ deployment_name: deploy_name.clone(),
84
+ }
85
+ .into_request(),
86
+ )
80
87
  .await
81
88
  },
82
89
  Duration::from_secs(5),
@@ -89,13 +96,16 @@ async fn sets_deployment_info_on_task_responses(#[values(true, false)] use_defau
89
96
  client
90
97
  .get_client()
91
98
  .clone()
92
- .set_worker_deployment_current_version(SetWorkerDeploymentCurrentVersionRequest {
93
- namespace: client.namespace().to_owned(),
94
- deployment_name: deploy_name.clone(),
95
- version: format!("{deploy_name}.1.0"),
96
- conflict_token: desc_resp.conflict_token,
97
- ..Default::default()
98
- })
99
+ .set_worker_deployment_current_version(
100
+ SetWorkerDeploymentCurrentVersionRequest {
101
+ namespace: client.namespace(),
102
+ deployment_name: deploy_name.clone(),
103
+ version: format!("{deploy_name}.1.0"),
104
+ conflict_token: desc_resp.conflict_token,
105
+ ..Default::default()
106
+ }
107
+ .into_request(),
108
+ )
99
109
  .await
100
110
  .unwrap();
101
111
 
@@ -175,10 +185,13 @@ async fn activity_has_deployment_stamp() {
175
185
  client
176
186
  .get_client()
177
187
  .clone()
178
- .describe_worker_deployment(DescribeWorkerDeploymentRequest {
179
- namespace: client.namespace().to_string(),
180
- deployment_name: deploy_name.clone(),
181
- })
188
+ .describe_worker_deployment(
189
+ DescribeWorkerDeploymentRequest {
190
+ namespace: client.namespace(),
191
+ deployment_name: deploy_name.clone(),
192
+ }
193
+ .into_request(),
194
+ )
182
195
  .await
183
196
  },
184
197
  Duration::from_secs(50),
@@ -191,13 +204,16 @@ async fn activity_has_deployment_stamp() {
191
204
  client
192
205
  .get_client()
193
206
  .clone()
194
- .set_worker_deployment_current_version(SetWorkerDeploymentCurrentVersionRequest {
195
- namespace: client.namespace().to_owned(),
196
- deployment_name: deploy_name.clone(),
197
- version: format!("{deploy_name}.1.0"),
198
- conflict_token: desc_resp.conflict_token,
199
- ..Default::default()
200
- })
207
+ .set_worker_deployment_current_version(
208
+ SetWorkerDeploymentCurrentVersionRequest {
209
+ namespace: client.namespace(),
210
+ deployment_name: deploy_name.clone(),
211
+ version: format!("{deploy_name}.1.0"),
212
+ conflict_token: desc_resp.conflict_token,
213
+ ..Default::default()
214
+ }
215
+ .into_request(),
216
+ )
201
217
  .await
202
218
  .unwrap();
203
219
 
@@ -1,4 +1,10 @@
1
- use crate::integ_tests::activity_functions::echo;
1
+ use crate::{
2
+ common::{
3
+ ActivationAssertionsInterceptor, CoreWfStarter, INTEG_CLIENT_IDENTITY, build_fake_sdk,
4
+ eventually, init_core_and_create_wf, mock_sdk, mock_sdk_cfg,
5
+ },
6
+ integ_tests::activity_functions::echo,
7
+ };
2
8
  use anyhow::anyhow;
3
9
  use assert_matches::assert_matches;
4
10
  use futures_util::future::join_all;
@@ -9,14 +15,17 @@ use std::{
9
15
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
10
16
  use temporal_sdk::{
11
17
  ActContext, ActExitValue, ActivityError, ActivityOptions, CancellableFuture, WfContext,
12
- WfExitValue, WorkflowResult,
18
+ WfExitValue, WorkflowFunction, WorkflowResult,
19
+ };
20
+ use temporal_sdk_core::test_help::{
21
+ MockPollCfg, ResponseType, WorkerTestHelpers, drain_pollers_and_shutdown, mock_worker_client,
13
22
  };
14
23
  use temporal_sdk_core_api::worker::PollerBehavior;
15
24
  use temporal_sdk_core_protos::{
16
- DEFAULT_ACTIVITY_TYPE, TaskToken,
25
+ DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE, TaskToken, TestHistoryBuilder, canned_histories,
17
26
  coresdk::{
18
27
  ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, FromJsonPayloadExt,
19
- IntoCompletion,
28
+ IntoCompletion, IntoPayloadsExt,
20
29
  activity_result::{
21
30
  self, ActivityExecutionResult, ActivityResolution, activity_resolution as act_res,
22
31
  },
@@ -29,15 +38,14 @@ use temporal_sdk_core_protos::{
29
38
  },
30
39
  workflow_completion::WorkflowActivationCompletion,
31
40
  },
41
+ prost_dur,
32
42
  temporal::api::{
33
43
  common::v1::{ActivityType, Payload, Payloads, RetryPolicy},
34
- enums::v1::RetryState,
44
+ enums::v1::{CommandType, EventType, RetryState},
35
45
  failure::v1::{ActivityFailureInfo, Failure, failure::FailureInfo},
46
+ sdk::v1::UserMetadata,
36
47
  },
37
- };
38
- use temporal_sdk_core_test_utils::{
39
- CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, init_core_and_create_wf,
40
- schedule_activity_cmd,
48
+ test_utils::schedule_activity_cmd,
41
49
  };
42
50
  use tokio::{join, sync::Semaphore, time::sleep};
43
51
 
@@ -198,7 +206,7 @@ async fn activity_non_retryable_failure() {
198
206
  }),
199
207
  scheduled_event_id: 5,
200
208
  started_event_id: 6,
201
- identity: "integ_tester".to_owned(),
209
+ identity: INTEG_CLIENT_IDENTITY.to_owned(),
202
210
  retry_state: RetryState::NonRetryableFailure as i32,
203
211
  })),
204
212
  ..Default::default()
@@ -265,7 +273,7 @@ async fn activity_non_retryable_failure_with_error() {
265
273
  }),
266
274
  scheduled_event_id: 5,
267
275
  started_event_id: 6,
268
- identity: "integ_tester".to_owned(),
276
+ identity: INTEG_CLIENT_IDENTITY.to_owned(),
269
277
  retry_state: RetryState::NonRetryableFailure as i32,
270
278
  })),
271
279
  ..Default::default()
@@ -790,6 +798,86 @@ async fn activity_cancelled_after_heartbeat_times_out() {
790
798
  .unwrap();
791
799
  }
792
800
 
801
+ #[ignore] // Currently skipped because of https://github.com/temporalio/temporal/issues/8376
802
+ #[tokio::test]
803
+ async fn activity_heartbeat_not_flushed_on_success() {
804
+ let mut starter = init_core_and_create_wf("activity_heartbeat_not_flushed_on_success").await;
805
+ let core = starter.get_worker().await;
806
+ let task_q = starter.get_task_queue().to_string();
807
+ let activity_id = "act-1";
808
+ let task = core.poll_workflow_activation().await.unwrap();
809
+ core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
810
+ task.run_id,
811
+ ScheduleActivity {
812
+ seq: 0,
813
+ activity_id: activity_id.to_string(),
814
+ activity_type: "dontcare".to_string(),
815
+ task_queue: task_q.clone(),
816
+ schedule_to_close_timeout: Some(prost_dur!(from_secs(60))),
817
+ heartbeat_timeout: Some(prost_dur!(from_secs(10))),
818
+ retry_policy: Some(RetryPolicy {
819
+ maximum_attempts: 2,
820
+ initial_interval: Some(prost_dur!(from_secs(5))),
821
+ ..Default::default()
822
+ }),
823
+ ..Default::default()
824
+ }
825
+ .into(),
826
+ ))
827
+ .await
828
+ .unwrap();
829
+ // Poll activity and verify that it's been scheduled
830
+ let task = core.poll_activity_task().await.unwrap();
831
+ assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
832
+ // heartbeat 1 (will send immediately)
833
+ core.record_activity_heartbeat(ActivityHeartbeat {
834
+ task_token: task.task_token.clone(),
835
+ details: vec!["one".into()],
836
+ });
837
+ // heartbeat 2 (would be throttled if not flushed)
838
+ core.record_activity_heartbeat(ActivityHeartbeat {
839
+ task_token: task.task_token.clone(),
840
+ details: vec!["two".into()],
841
+ });
842
+ // Complete activity with fail
843
+ let failure = Failure::application_failure("activity failed".to_string(), false);
844
+ core.complete_activity_task(ActivityTaskCompletion {
845
+ task_token: task.task_token,
846
+ result: Some(ActivityExecutionResult::fail(failure)),
847
+ })
848
+ .await
849
+ .unwrap();
850
+ // The activity is still in the pending state since it has retries left
851
+ let client = starter.get_client().await;
852
+ eventually(
853
+ || async {
854
+ // Verify pending details has the flushed heartbeat
855
+ let details = client
856
+ .describe_workflow_execution(starter.get_wf_id().to_string(), None)
857
+ .await
858
+ .unwrap();
859
+ let last_deets = details
860
+ .pending_activities
861
+ .into_iter()
862
+ .find(|i| i.activity_id == activity_id)
863
+ .and_then(|i| i.heartbeat_details);
864
+ if last_deets == ["two".into()].into_payloads() {
865
+ Ok(())
866
+ } else {
867
+ Err("details don't yet match")
868
+ }
869
+ },
870
+ Duration::from_secs(5),
871
+ )
872
+ .await
873
+ .unwrap();
874
+ client
875
+ .terminate_workflow_execution(task_q, None)
876
+ .await
877
+ .unwrap();
878
+ drain_pollers_and_shutdown(&core).await;
879
+ }
880
+
793
881
  #[tokio::test]
794
882
  async fn one_activity_abandon_cancelled_before_started() {
795
883
  let wf_name = "one_activity_abandon_cancelled_before_started";
@@ -1114,3 +1202,148 @@ async fn long_activity_timeout_repro() {
1114
1202
  starter.start_with_worker(wf_name, &mut worker).await;
1115
1203
  worker.run_until_done().await.unwrap();
1116
1204
  }
1205
+
1206
+ #[tokio::test]
1207
+ async fn pass_activity_summary_to_metadata() {
1208
+ let t = canned_histories::single_activity("1");
1209
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
1210
+ let wf_id = mock_cfg.hists[0].wf_id.clone();
1211
+ let wf_type = DEFAULT_WORKFLOW_TYPE;
1212
+ let expected_user_metadata = Some(UserMetadata {
1213
+ summary: Some(b"activity summary".into()),
1214
+ details: None,
1215
+ });
1216
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
1217
+ asserts
1218
+ .then(move |wft| {
1219
+ assert_eq!(wft.commands.len(), 1);
1220
+ assert_eq!(
1221
+ wft.commands[0].command_type(),
1222
+ CommandType::ScheduleActivityTask
1223
+ );
1224
+ assert_eq!(wft.commands[0].user_metadata, expected_user_metadata)
1225
+ })
1226
+ .then(move |wft| {
1227
+ assert_eq!(wft.commands.len(), 1);
1228
+ assert_eq!(
1229
+ wft.commands[0].command_type(),
1230
+ CommandType::CompleteWorkflowExecution
1231
+ );
1232
+ });
1233
+ });
1234
+
1235
+ let mut worker = mock_sdk_cfg(mock_cfg, |_| {});
1236
+ worker.register_wf(wf_type, |ctx: WfContext| async move {
1237
+ ctx.activity(ActivityOptions {
1238
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1239
+ summary: Some("activity summary".to_string()),
1240
+ ..Default::default()
1241
+ })
1242
+ .await;
1243
+ Ok(().into())
1244
+ });
1245
+ worker
1246
+ .submit_wf(
1247
+ wf_id.to_owned(),
1248
+ wf_type.to_owned(),
1249
+ vec![],
1250
+ WorkflowOptions::default(),
1251
+ )
1252
+ .await
1253
+ .unwrap();
1254
+ worker.run_until_done().await.unwrap();
1255
+ }
1256
+
1257
+ #[rstest(hist_batches, case::incremental(&[1, 2, 3, 4]), case::replay(&[4]))]
1258
+ #[tokio::test]
1259
+ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [usize]) {
1260
+ let wfid = "fake_wf_id";
1261
+ let wf_type = DEFAULT_WORKFLOW_TYPE;
1262
+ let activity_id = "1";
1263
+
1264
+ let mut t = TestHistoryBuilder::default();
1265
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1266
+ t.add_full_wf_task();
1267
+ let act_scheduled_event_id = t.add_activity_task_scheduled(activity_id);
1268
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1269
+ t.add_timer_fired(timer_started_event_id, "1".to_string());
1270
+ t.add_full_wf_task();
1271
+ let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
1272
+ let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
1273
+ t.add_activity_task_completed(
1274
+ act_scheduled_event_id,
1275
+ act_started_event_id,
1276
+ Default::default(),
1277
+ );
1278
+ t.add_full_wf_task();
1279
+ t.add_timer_fired(timer_started_event_id, "2".to_string());
1280
+ t.add_full_wf_task();
1281
+ t.add_workflow_execution_completed();
1282
+ let mock = mock_worker_client();
1283
+ let mut worker = mock_sdk(MockPollCfg::from_resp_batches(wfid, t, hist_batches, mock));
1284
+
1285
+ worker.register_wf(wf_type.to_owned(), |ctx: WfContext| async move {
1286
+ let act_fut = ctx.activity(ActivityOptions {
1287
+ activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
1288
+ start_to_close_timeout: Some(Duration::from_secs(5)),
1289
+ cancellation_type: ActivityCancellationType::Abandon,
1290
+ ..Default::default()
1291
+ });
1292
+ ctx.timer(Duration::from_secs(1)).await;
1293
+ act_fut.cancel(&ctx);
1294
+ ctx.timer(Duration::from_secs(3)).await;
1295
+ act_fut.await;
1296
+ Ok(().into())
1297
+ });
1298
+ worker
1299
+ .submit_wf(wfid, wf_type, vec![], Default::default())
1300
+ .await
1301
+ .unwrap();
1302
+ worker.run_until_done().await.unwrap();
1303
+ }
1304
+
1305
+ #[tokio::test]
1306
+ async fn immediate_activity_cancelation() {
1307
+ let func = WorkflowFunction::new(|ctx: WfContext| async move {
1308
+ let cancel_activity_future = ctx.activity(ActivityOptions::default());
1309
+ // Immediately cancel the activity
1310
+ cancel_activity_future.cancel(&ctx);
1311
+ cancel_activity_future.await;
1312
+ Ok(().into())
1313
+ });
1314
+
1315
+ let mut t = TestHistoryBuilder::default();
1316
+ t.add_by_type(EventType::WorkflowExecutionStarted);
1317
+ t.add_full_wf_task();
1318
+ t.add_workflow_execution_completed();
1319
+ let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
1320
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
1321
+
1322
+ let mut aai = ActivationAssertionsInterceptor::default();
1323
+ aai.then(|a| {
1324
+ assert_matches!(
1325
+ a.jobs.as_slice(),
1326
+ [WorkflowActivationJob {
1327
+ variant: Some(workflow_activation_job::Variant::InitializeWorkflow(_)),
1328
+ }]
1329
+ )
1330
+ });
1331
+ aai.then(|a| {
1332
+ assert_matches!(
1333
+ a.jobs.as_slice(),
1334
+ [WorkflowActivationJob {
1335
+ variant: Some(workflow_activation_job::Variant::ResolveActivity(
1336
+ ResolveActivity {
1337
+ result: Some(ActivityResolution {
1338
+ status: Some(act_res::Status::Cancelled(_))
1339
+ }),
1340
+ ..
1341
+ }
1342
+ )),
1343
+ },]
1344
+ )
1345
+ });
1346
+
1347
+ worker.set_worker_interceptor(aai);
1348
+ worker.run().await.unwrap();
1349
+ }
@@ -1,9 +1,9 @@
1
+ use crate::common::CoreWfStarter;
1
2
  use assert_matches::assert_matches;
2
3
  use std::time::Duration;
3
4
  use temporal_client::{WfClientExt, WorkflowExecutionResult, WorkflowOptions};
4
5
  use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
5
6
  use temporal_sdk_core_protos::coresdk::AsJsonPayloadExt;
6
- use temporal_sdk_core_test_utils::CoreWfStarter;
7
7
 
8
8
  const TEST_APPDATA_MESSAGE: &str = "custom app data, yay";
9
9
 
@@ -1,7 +1,12 @@
1
+ use crate::common::{CoreWfStarter, build_fake_sdk};
1
2
  use temporal_client::{GetWorkflowResultOpts, WfClientExt, WorkflowOptions};
2
3
  use temporal_sdk::{WfContext, WorkflowResult};
3
- use temporal_sdk_core_protos::coresdk::{FromJsonPayloadExt, common::NamespacedWorkflowExecution};
4
- use temporal_sdk_core_test_utils::CoreWfStarter;
4
+ use temporal_sdk_core::test_help::MockPollCfg;
5
+ use temporal_sdk_core_protos::{
6
+ DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder,
7
+ coresdk::{FromJsonPayloadExt, common::NamespacedWorkflowExecution},
8
+ temporal::api::enums::v1::{CommandType, EventType},
9
+ };
5
10
 
6
11
  const RECEIVER_WFID: &str = "sends-cancel-receiver";
7
12
 
@@ -72,3 +77,74 @@ async fn sends_cancel_to_other_wf() {
72
77
  assert!(res.contains("Cancel requested by workflow"));
73
78
  assert!(res.contains("cancel-reason"));
74
79
  }
80
+
81
+ async fn cancel_sender_canned(ctx: WfContext) -> WorkflowResult<()> {
82
+ let res = ctx
83
+ .cancel_external(
84
+ NamespacedWorkflowExecution {
85
+ namespace: "some_namespace".to_string(),
86
+ workflow_id: "fake_wid".to_string(),
87
+ run_id: "fake_rid".to_string(),
88
+ },
89
+ "cancel reason".to_string(),
90
+ )
91
+ .await;
92
+ if res.is_err() {
93
+ Err(anyhow::anyhow!("Cancel fail!"))
94
+ } else {
95
+ Ok(().into())
96
+ }
97
+ }
98
+
99
+ #[rstest::rstest]
100
+ #[case::succeeds(false)]
101
+ #[case::fails(true)]
102
+ #[tokio::test]
103
+ async fn sends_cancel_canned(#[case] fails: bool) {
104
+ let mut t = TestHistoryBuilder::default();
105
+ t.add_by_type(EventType::WorkflowExecutionStarted);
106
+ t.add_full_wf_task();
107
+ let id = t.add_cancel_external_wf(NamespacedWorkflowExecution {
108
+ namespace: "some_namespace".to_string(),
109
+ workflow_id: "fake_wid".to_string(),
110
+ run_id: "fake_rid".to_string(),
111
+ });
112
+ if fails {
113
+ t.add_cancel_external_wf_failed(id);
114
+ } else {
115
+ t.add_cancel_external_wf_completed(id);
116
+ }
117
+ t.add_full_wf_task();
118
+ if fails {
119
+ t.add_workflow_execution_failed();
120
+ } else {
121
+ t.add_workflow_execution_completed();
122
+ }
123
+
124
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
125
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
126
+ asserts
127
+ .then(|wft| {
128
+ assert_matches!(
129
+ wft.commands[0].command_type(),
130
+ CommandType::RequestCancelExternalWorkflowExecution
131
+ );
132
+ })
133
+ .then(move |wft| {
134
+ if fails {
135
+ assert_eq!(
136
+ wft.commands[0].command_type(),
137
+ CommandType::FailWorkflowExecution
138
+ );
139
+ } else {
140
+ assert_eq!(
141
+ wft.commands[0].command_type(),
142
+ CommandType::CompleteWorkflowExecution
143
+ );
144
+ }
145
+ });
146
+ });
147
+ let mut worker = build_fake_sdk(mock_cfg);
148
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, cancel_sender_canned);
149
+ worker.run().await.unwrap();
150
+ }
@@ -1,8 +1,13 @@
1
+ use crate::common::{ActivationAssertionsInterceptor, CoreWfStarter, build_fake_sdk};
1
2
  use std::time::Duration;
2
3
  use temporal_client::WorkflowClientTrait;
3
4
  use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
4
- use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowExecutionStatus;
5
- use temporal_sdk_core_test_utils::CoreWfStarter;
5
+ use temporal_sdk_core::test_help::MockPollCfg;
6
+ use temporal_sdk_core_protos::{
7
+ DEFAULT_WORKFLOW_TYPE, canned_histories,
8
+ coresdk::workflow_activation::{WorkflowActivationJob, workflow_activation_job},
9
+ temporal::api::enums::v1::{CommandType, WorkflowExecutionStatus},
10
+ };
6
11
 
7
12
  async fn cancelled_wf(ctx: WfContext) -> WorkflowResult<()> {
8
13
  let mut reason = "".to_string();
@@ -55,3 +60,57 @@ async fn cancel_during_timer() {
55
60
  WorkflowExecutionStatus::Canceled as i32
56
61
  );
57
62
  }
63
+
64
+ async fn wf_with_timer(ctx: WfContext) -> WorkflowResult<()> {
65
+ ctx.timer(Duration::from_millis(500)).await;
66
+ Ok(WfExitValue::Cancelled)
67
+ }
68
+
69
+ #[tokio::test]
70
+ async fn wf_completing_with_cancelled() {
71
+ let t = canned_histories::timer_wf_cancel_req_cancelled("1");
72
+
73
+ let mut aai = ActivationAssertionsInterceptor::default();
74
+ aai.then(|a| {
75
+ assert_matches!(
76
+ a.jobs.as_slice(),
77
+ [WorkflowActivationJob {
78
+ variant: Some(workflow_activation_job::Variant::InitializeWorkflow(_)),
79
+ }]
80
+ )
81
+ });
82
+ aai.then(|a| {
83
+ assert_matches!(
84
+ a.jobs.as_slice(),
85
+ [
86
+ WorkflowActivationJob {
87
+ variant: Some(workflow_activation_job::Variant::FireTimer(_)),
88
+ },
89
+ WorkflowActivationJob {
90
+ variant: Some(workflow_activation_job::Variant::CancelWorkflow(_)),
91
+ }
92
+ ]
93
+ );
94
+ });
95
+
96
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
97
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
98
+ asserts
99
+ .then(|wft| {
100
+ assert_eq!(wft.commands.len(), 1);
101
+ assert_matches!(wft.commands[0].command_type(), CommandType::StartTimer);
102
+ })
103
+ .then(move |wft| {
104
+ assert_eq!(wft.commands.len(), 1);
105
+ assert_matches!(
106
+ wft.commands[0].command_type(),
107
+ CommandType::CancelWorkflowExecution
108
+ );
109
+ });
110
+ });
111
+
112
+ let mut worker = build_fake_sdk(mock_cfg);
113
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, wf_with_timer);
114
+ worker.set_worker_interceptor(aai);
115
+ worker.run().await.unwrap();
116
+ }