@temporalio/core-bridge 1.11.8 → 1.12.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 (205) hide show
  1. package/Cargo.lock +219 -193
  2. package/Cargo.toml +27 -8
  3. package/README.md +5 -0
  4. package/index.js +72 -12
  5. package/lib/errors.d.ts +25 -0
  6. package/lib/errors.js +76 -1
  7. package/lib/errors.js.map +1 -1
  8. package/lib/index.d.ts +11 -478
  9. package/lib/index.js +28 -5
  10. package/lib/index.js.map +1 -1
  11. package/lib/native.d.ts +330 -0
  12. package/lib/{worker-tuner.js → native.js} +1 -1
  13. package/lib/native.js.map +1 -0
  14. package/package.json +7 -3
  15. package/releases/aarch64-apple-darwin/index.node +0 -0
  16. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  17. package/releases/x86_64-apple-darwin/index.node +0 -0
  18. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  19. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  20. package/sdk-core/.cargo/config.toml +8 -2
  21. package/sdk-core/.cargo/multi-worker-manual-test +15 -0
  22. package/sdk-core/.github/workflows/per-pr.yml +40 -11
  23. package/sdk-core/AGENTS.md +73 -0
  24. package/sdk-core/ARCHITECTURE.md +71 -23
  25. package/sdk-core/Cargo.toml +1 -1
  26. package/sdk-core/README.md +4 -4
  27. package/sdk-core/arch_docs/workflow_task_chunking.md +51 -0
  28. package/sdk-core/client/Cargo.toml +1 -1
  29. package/sdk-core/client/src/lib.rs +49 -13
  30. package/sdk-core/client/src/metrics.rs +15 -16
  31. package/sdk-core/client/src/proxy.rs +2 -2
  32. package/sdk-core/client/src/raw.rs +54 -8
  33. package/sdk-core/client/src/retry.rs +109 -13
  34. package/sdk-core/client/src/worker_registry/mod.rs +4 -4
  35. package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
  36. package/sdk-core/core/Cargo.toml +28 -8
  37. package/sdk-core/core/src/abstractions.rs +62 -10
  38. package/sdk-core/core/src/core_tests/activity_tasks.rs +180 -8
  39. package/sdk-core/core/src/core_tests/mod.rs +4 -4
  40. package/sdk-core/core/src/core_tests/queries.rs +18 -4
  41. package/sdk-core/core/src/core_tests/workers.rs +3 -3
  42. package/sdk-core/core/src/core_tests/workflow_tasks.rs +191 -25
  43. package/sdk-core/core/src/ephemeral_server/mod.rs +10 -3
  44. package/sdk-core/core/src/internal_flags.rs +14 -14
  45. package/sdk-core/core/src/lib.rs +5 -2
  46. package/sdk-core/core/src/pollers/mod.rs +1 -1
  47. package/sdk-core/core/src/pollers/poll_buffer.rs +495 -164
  48. package/sdk-core/core/src/protosext/mod.rs +3 -3
  49. package/sdk-core/core/src/replay/mod.rs +3 -3
  50. package/sdk-core/core/src/telemetry/metrics.rs +13 -4
  51. package/sdk-core/core/src/telemetry/mod.rs +72 -70
  52. package/sdk-core/core/src/telemetry/otel.rs +51 -54
  53. package/sdk-core/core/src/test_help/mod.rs +9 -3
  54. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +31 -11
  55. package/sdk-core/core/src/worker/activities/local_activities.rs +35 -28
  56. package/sdk-core/core/src/worker/activities.rs +58 -30
  57. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  58. package/sdk-core/core/src/worker/client.rs +155 -53
  59. package/sdk-core/core/src/worker/mod.rs +103 -95
  60. package/sdk-core/core/src/worker/nexus.rs +100 -73
  61. package/sdk-core/core/src/worker/tuner/resource_based.rs +14 -6
  62. package/sdk-core/core/src/worker/tuner.rs +4 -13
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +47 -51
  64. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -4
  65. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +127 -32
  66. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +1 -2
  67. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +1 -1
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +55 -42
  69. package/sdk-core/core/src/worker/workflow/managed_run.rs +45 -35
  70. package/sdk-core/core/src/worker/workflow/mod.rs +200 -97
  71. package/sdk-core/core/src/worker/workflow/wft_poller.rs +175 -4
  72. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +38 -36
  73. package/sdk-core/core-api/Cargo.toml +8 -0
  74. package/sdk-core/core-api/src/envconfig.rs +1544 -0
  75. package/sdk-core/core-api/src/lib.rs +2 -0
  76. package/sdk-core/core-api/src/telemetry/metrics.rs +8 -0
  77. package/sdk-core/core-api/src/telemetry.rs +36 -3
  78. package/sdk-core/core-api/src/worker.rs +301 -75
  79. package/sdk-core/docker/docker-compose-telem.yaml +1 -0
  80. package/sdk-core/etc/prometheus.yaml +6 -2
  81. package/sdk-core/histories/long_local_activity_with_update-0_history.bin +0 -0
  82. package/sdk-core/histories/long_local_activity_with_update-1_history.bin +0 -0
  83. package/sdk-core/histories/long_local_activity_with_update-2_history.bin +0 -0
  84. package/sdk-core/histories/long_local_activity_with_update-3_history.bin +0 -0
  85. package/sdk-core/sdk/src/activity_context.rs +5 -0
  86. package/sdk-core/sdk/src/interceptors.rs +73 -3
  87. package/sdk-core/sdk/src/lib.rs +15 -16
  88. package/sdk-core/sdk/src/workflow_context/options.rs +10 -0
  89. package/sdk-core/sdk/src/workflow_context.rs +48 -29
  90. package/sdk-core/sdk/src/workflow_future.rs +5 -6
  91. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/.github/workflows/push-to-buf.yml +20 -0
  92. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/CODEOWNERS +6 -0
  93. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +17 -6
  94. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -1
  95. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.lock +7 -2
  96. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +2 -0
  97. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +78 -0
  98. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +29 -0
  99. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +74 -32
  100. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +45 -15
  101. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/nexus/v1/message.proto +7 -1
  102. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +3 -3
  103. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +3 -3
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/LICENSE +1 -1
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +2 -0
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +1103 -88
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +1233 -151
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/activity/v1/message.proto +0 -22
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +19 -24
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +0 -22
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +12 -22
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +45 -45
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -22
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +0 -22
  115. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +15 -22
  116. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +0 -22
  117. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -22
  118. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +0 -22
  119. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/namespace.proto +0 -22
  120. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/nexus.proto +0 -20
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/query.proto +0 -22
  122. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +0 -22
  123. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/schedule.proto +0 -22
  124. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -22
  125. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +0 -22
  126. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -22
  127. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +0 -22
  128. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto +0 -22
  129. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -22
  130. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/filter/v1/message.proto +0 -22
  131. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +75 -49
  132. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +0 -22
  133. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +0 -20
  134. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +0 -22
  135. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -22
  136. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/protocol/v1/message.proto +0 -22
  137. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/query/v1/message.proto +0 -22
  138. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/replication/v1/message.proto +0 -22
  139. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/rules/v1/message.proto +90 -0
  140. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +0 -22
  141. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +0 -22
  142. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +0 -22
  143. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +0 -22
  144. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +0 -22
  145. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +17 -38
  146. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/update/v1/message.proto +0 -22
  147. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/version/v1/message.proto +0 -22
  148. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +151 -44
  149. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -65
  150. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +69 -28
  151. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/activity_task/activity_task.proto +18 -0
  152. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/common/common.proto +5 -0
  153. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/nexus/nexus.proto +16 -1
  154. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +21 -15
  155. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +3 -0
  156. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -0
  157. package/sdk-core/sdk-core-protos/src/lib.rs +60 -16
  158. package/sdk-core/test-utils/src/lib.rs +157 -39
  159. package/sdk-core/tests/cloud_tests.rs +86 -0
  160. package/sdk-core/tests/fuzzy_workflow.rs +23 -26
  161. package/sdk-core/tests/global_metric_tests.rs +116 -0
  162. package/sdk-core/tests/heavy_tests.rs +127 -7
  163. package/sdk-core/tests/integ_tests/client_tests.rs +2 -8
  164. package/sdk-core/tests/integ_tests/metrics_tests.rs +100 -106
  165. package/sdk-core/tests/integ_tests/polling_tests.rs +94 -8
  166. package/sdk-core/tests/integ_tests/update_tests.rs +75 -6
  167. package/sdk-core/tests/integ_tests/worker_tests.rs +54 -5
  168. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +240 -0
  169. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +41 -3
  170. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +168 -8
  171. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +285 -15
  172. package/sdk-core/tests/integ_tests/workflow_tests/priority.rs +12 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -2
  174. package/sdk-core/tests/integ_tests/workflow_tests.rs +124 -74
  175. package/sdk-core/tests/main.rs +3 -51
  176. package/sdk-core/tests/manual_tests.rs +430 -0
  177. package/sdk-core/tests/runner.rs +28 -2
  178. package/src/client.rs +565 -0
  179. package/src/helpers/abort_controller.rs +204 -0
  180. package/src/helpers/callbacks.rs +299 -0
  181. package/src/helpers/errors.rs +302 -0
  182. package/src/helpers/future.rs +44 -0
  183. package/src/helpers/handles.rs +191 -0
  184. package/src/helpers/inspect.rs +18 -0
  185. package/src/helpers/json_string.rs +58 -0
  186. package/src/helpers/mod.rs +20 -0
  187. package/src/helpers/properties.rs +71 -0
  188. package/src/helpers/try_from_js.rs +213 -0
  189. package/src/helpers/try_into_js.rs +129 -0
  190. package/src/lib.rs +28 -40
  191. package/src/logs.rs +111 -0
  192. package/src/metrics.rs +325 -0
  193. package/src/runtime.rs +409 -498
  194. package/src/testing.rs +315 -57
  195. package/src/worker.rs +907 -378
  196. package/ts/errors.ts +57 -0
  197. package/ts/index.ts +10 -596
  198. package/ts/native.ts +496 -0
  199. package/lib/worker-tuner.d.ts +0 -167
  200. package/lib/worker-tuner.js.map +0 -1
  201. package/src/conversions/slot_supplier_bridge.rs +0 -291
  202. package/src/conversions.rs +0 -618
  203. package/src/errors.rs +0 -38
  204. package/src/helpers.rs +0 -297
  205. package/ts/worker-tuner.ts +0 -193
@@ -0,0 +1,240 @@
1
+ use crate::integ_tests::activity_functions::echo;
2
+ use std::time::Duration;
3
+ use temporal_client::{NamespacedClient, WorkflowOptions, WorkflowService};
4
+ use temporal_sdk::{ActivityOptions, WfContext};
5
+ use temporal_sdk_core_api::worker::{
6
+ WorkerDeploymentOptions, WorkerDeploymentVersion, WorkerVersioningStrategy,
7
+ };
8
+ use temporal_sdk_core_protos::{
9
+ coresdk::{
10
+ AsJsonPayloadExt, workflow_commands::CompleteWorkflowExecution, workflow_completion,
11
+ workflow_completion::WorkflowActivationCompletion,
12
+ },
13
+ temporal::api::{
14
+ enums::v1::VersioningBehavior,
15
+ history::v1::history_event::Attributes,
16
+ workflowservice::v1::{
17
+ DescribeWorkerDeploymentRequest, SetWorkerDeploymentCurrentVersionRequest,
18
+ },
19
+ },
20
+ };
21
+ use temporal_sdk_core_test_utils::{CoreWfStarter, WorkerTestHelpers, eventually};
22
+ use tokio::join;
23
+
24
+ #[rstest::rstest]
25
+ #[tokio::test]
26
+ async fn sets_deployment_info_on_task_responses(#[values(true, false)] use_default: bool) {
27
+ let wf_type = "sets_deployment_info_on_task_responses";
28
+ let mut starter = CoreWfStarter::new(wf_type);
29
+ let deploy_name = format!("deployment-{}", starter.get_task_queue());
30
+ let version = WorkerDeploymentVersion {
31
+ deployment_name: deploy_name.clone(),
32
+ build_id: "1.0".to_string(),
33
+ };
34
+ starter
35
+ .worker_config
36
+ .versioning_strategy(WorkerVersioningStrategy::WorkerDeploymentBased(
37
+ WorkerDeploymentOptions {
38
+ version: version.clone(),
39
+ use_worker_versioning: true,
40
+ default_versioning_behavior: VersioningBehavior::AutoUpgrade.into(),
41
+ },
42
+ ))
43
+ .no_remote_activities(true);
44
+ let core = starter.get_worker().await;
45
+ let client = starter.get_client().await;
46
+
47
+ // A bit annoying. We have to start up polling here so that the deployment will exist before
48
+ // we can describe it and then set the current version.
49
+ let worker_task = async {
50
+ let res = core.poll_workflow_activation().await.unwrap();
51
+ assert_eq!(
52
+ version,
53
+ res.deployment_version_for_current_task.unwrap().into(),
54
+ );
55
+
56
+ let mut success_complete = workflow_completion::Success::from_variants(vec![
57
+ CompleteWorkflowExecution { result: None }.into(),
58
+ ]);
59
+ if !use_default {
60
+ success_complete.versioning_behavior = VersioningBehavior::Pinned.into();
61
+ }
62
+ core.complete_workflow_activation(WorkflowActivationCompletion {
63
+ run_id: res.run_id.clone(),
64
+ status: Some(success_complete.into()),
65
+ })
66
+ .await
67
+ .unwrap();
68
+ };
69
+
70
+ let ops_task = async {
71
+ let desc_resp = eventually(
72
+ async || {
73
+ client
74
+ .get_client()
75
+ .clone()
76
+ .describe_worker_deployment(DescribeWorkerDeploymentRequest {
77
+ namespace: client.namespace().to_string(),
78
+ deployment_name: deploy_name.clone(),
79
+ })
80
+ .await
81
+ },
82
+ Duration::from_secs(5),
83
+ )
84
+ .await
85
+ .unwrap()
86
+ .into_inner();
87
+
88
+ #[allow(deprecated)]
89
+ client
90
+ .get_client()
91
+ .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
+ .await
100
+ .unwrap();
101
+
102
+ starter.start_wf().await;
103
+ };
104
+
105
+ join!(worker_task, ops_task);
106
+ core.handle_eviction().await;
107
+ core.shutdown().await;
108
+
109
+ // Fetch history & verify task complete is properly stamped
110
+ let history = starter.get_history().await;
111
+ let wft_complete = history
112
+ .events
113
+ .into_iter()
114
+ .find_map(|e| {
115
+ if let Attributes::WorkflowTaskCompletedEventAttributes(a) = e.attributes.unwrap() {
116
+ Some(a)
117
+ } else {
118
+ None
119
+ }
120
+ })
121
+ .unwrap();
122
+ if use_default {
123
+ assert_eq!(
124
+ wft_complete.versioning_behavior,
125
+ VersioningBehavior::AutoUpgrade as i32
126
+ );
127
+ } else {
128
+ assert_eq!(
129
+ wft_complete.versioning_behavior,
130
+ VersioningBehavior::Pinned as i32
131
+ );
132
+ }
133
+ assert_eq!(wft_complete.worker_deployment_name, deploy_name);
134
+ #[allow(deprecated)] // odd looking hack since can't put attr macro on macro
135
+ {
136
+ assert_eq!(
137
+ wft_complete.worker_deployment_version,
138
+ format!("{deploy_name}.1.0")
139
+ );
140
+ }
141
+ }
142
+
143
+ #[tokio::test]
144
+ async fn activity_has_deployment_stamp() {
145
+ let wf_name = "activity_has_deployment_stamp";
146
+ let mut starter = CoreWfStarter::new(wf_name);
147
+ let deploy_name = format!("deployment-{}", starter.get_task_queue());
148
+ starter
149
+ .worker_config
150
+ .versioning_strategy(WorkerVersioningStrategy::WorkerDeploymentBased(
151
+ WorkerDeploymentOptions {
152
+ version: WorkerDeploymentVersion {
153
+ deployment_name: deploy_name.clone(),
154
+ build_id: "1.0".to_string(),
155
+ },
156
+ use_worker_versioning: true,
157
+ default_versioning_behavior: VersioningBehavior::AutoUpgrade.into(),
158
+ },
159
+ ));
160
+ let mut worker = starter.worker().await;
161
+ let client = starter.get_client().await;
162
+ worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
163
+ ctx.activity(ActivityOptions {
164
+ activity_type: "echo_activity".to_string(),
165
+ start_to_close_timeout: Some(Duration::from_secs(5)),
166
+ input: "hi!".as_json_payload().expect("serializes fine"),
167
+ ..Default::default()
168
+ })
169
+ .await;
170
+ Ok(().into())
171
+ });
172
+ worker.register_activity("echo_activity", echo);
173
+ let submitter = worker.get_submitter_handle();
174
+ let shutdown_handle = worker.inner_mut().shutdown_handle();
175
+
176
+ let client_task = async {
177
+ let desc_resp = eventually(
178
+ async || {
179
+ client
180
+ .get_client()
181
+ .clone()
182
+ .describe_worker_deployment(DescribeWorkerDeploymentRequest {
183
+ namespace: client.namespace().to_string(),
184
+ deployment_name: deploy_name.clone(),
185
+ })
186
+ .await
187
+ },
188
+ Duration::from_secs(50),
189
+ )
190
+ .await
191
+ .unwrap()
192
+ .into_inner();
193
+
194
+ #[allow(deprecated)]
195
+ client
196
+ .get_client()
197
+ .clone()
198
+ .set_worker_deployment_current_version(SetWorkerDeploymentCurrentVersionRequest {
199
+ namespace: client.namespace().to_owned(),
200
+ deployment_name: deploy_name.clone(),
201
+ version: format!("{deploy_name}.1.0"),
202
+ conflict_token: desc_resp.conflict_token,
203
+ ..Default::default()
204
+ })
205
+ .await
206
+ .unwrap();
207
+
208
+ submitter
209
+ .submit_wf(
210
+ starter.get_wf_id(),
211
+ wf_name.to_owned(),
212
+ vec![],
213
+ WorkflowOptions::default(),
214
+ )
215
+ .await
216
+ .unwrap();
217
+ starter.wait_for_default_wf_finish().await.unwrap();
218
+ shutdown_handle();
219
+ };
220
+ join!(
221
+ async {
222
+ worker.inner_mut().run().await.unwrap();
223
+ },
224
+ client_task
225
+ );
226
+ let hist = starter.get_history().await;
227
+ let _activity_completed = hist
228
+ .events
229
+ .into_iter()
230
+ .find_map(|e| {
231
+ if let Attributes::ActivityTaskCompletedEventAttributes(a) = e.attributes.unwrap() {
232
+ Some(a)
233
+ } else {
234
+ None
235
+ }
236
+ })
237
+ .unwrap();
238
+ // TODO: Can't actually verify this at the moment as the deployment options are not transferred
239
+ // to the event.
240
+ }
@@ -1,9 +1,10 @@
1
1
  use std::{
2
- sync::atomic::{AtomicUsize, Ordering},
2
+ sync::atomic::{AtomicBool, AtomicUsize, Ordering},
3
3
  time::Duration,
4
4
  };
5
- use temporal_sdk::{ActivityOptions, WfContext, WorkflowResult};
6
- use temporal_sdk_core_test_utils::CoreWfStarter;
5
+ use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
6
+ use temporal_sdk_core_protos::coresdk::AsJsonPayloadExt;
7
+ use temporal_sdk_core_test_utils::{CoreWfStarter, WorkflowHandleExt};
7
8
 
8
9
  static RUN_CT: AtomicUsize = AtomicUsize::new(1);
9
10
 
@@ -45,3 +46,40 @@ async fn test_determinism_error_then_recovers() {
45
46
  // 4 because we still add on the 3rd and final attempt
46
47
  assert_eq!(RUN_CT.load(Ordering::Relaxed), 4);
47
48
  }
49
+
50
+ #[tokio::test]
51
+ async fn task_fail_causes_replay_unset_too_soon() {
52
+ let wf_name = "task_fail_causes_replay_unset_too_soon";
53
+ let mut starter = CoreWfStarter::new(wf_name);
54
+ let mut worker = starter.worker().await;
55
+
56
+ static DID_FAIL: AtomicBool = AtomicBool::new(false);
57
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
58
+ if DID_FAIL.load(Ordering::Relaxed) {
59
+ assert!(ctx.is_replaying());
60
+ }
61
+ ctx.activity(ActivityOptions {
62
+ activity_type: "echo".to_string(),
63
+ input: "hi!".as_json_payload().expect("serializes fine"),
64
+ start_to_close_timeout: Some(Duration::from_secs(2)),
65
+ ..Default::default()
66
+ })
67
+ .await;
68
+ if !DID_FAIL.load(Ordering::Relaxed) {
69
+ DID_FAIL.store(true, Ordering::Relaxed);
70
+ panic!("Die on purpose");
71
+ }
72
+ Ok(().into())
73
+ });
74
+ worker.register_activity("echo", |_ctx: ActContext, echo_me: String| async move {
75
+ Ok(echo_me)
76
+ });
77
+
78
+ let handle = starter.start_with_worker(wf_name, &mut worker).await;
79
+
80
+ worker.run_until_done().await.unwrap();
81
+ handle
82
+ .fetch_history_and_replay(worker.inner_mut())
83
+ .await
84
+ .unwrap();
85
+ }
@@ -1,29 +1,38 @@
1
1
  use crate::integ_tests::activity_functions::echo;
2
2
  use anyhow::anyhow;
3
3
  use futures_util::future::join_all;
4
+ use rstest::Context;
4
5
  use std::{
5
- sync::atomic::{AtomicU8, Ordering},
6
+ sync::{
7
+ Arc,
8
+ atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering},
9
+ },
6
10
  time::Duration,
7
11
  };
8
- use temporal_client::{WfClientExt, WorkflowOptions};
12
+ use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
9
13
  use temporal_sdk::{
10
- ActContext, ActivityError, ActivityOptions, CancellableFuture, LocalActivityOptions, WfContext,
11
- WorkflowResult, interceptors::WorkerInterceptor,
14
+ ActContext, ActivityError, ActivityOptions, CancellableFuture, LocalActivityOptions,
15
+ UpdateContext, WfContext, WorkflowResult,
16
+ interceptors::{FailOnNondeterminismInterceptor, WorkerInterceptor},
12
17
  };
13
18
  use temporal_sdk_core::replay::HistoryForReplay;
14
19
  use temporal_sdk_core_protos::{
15
20
  TestHistoryBuilder,
16
21
  coresdk::{
17
- AsJsonPayloadExt,
22
+ AsJsonPayloadExt, IntoPayloadsExt,
18
23
  workflow_commands::{ActivityCancellationType, workflow_command::Variant},
19
24
  workflow_completion,
20
25
  workflow_completion::{WorkflowActivationCompletion, workflow_activation_completion},
21
26
  },
22
- temporal::api::{common::v1::RetryPolicy, enums::v1::TimeoutType},
27
+ temporal::api::{
28
+ common::v1::RetryPolicy,
29
+ enums::v1::{TimeoutType, UpdateWorkflowExecutionLifecycleStage},
30
+ update::v1::WaitPolicy,
31
+ },
23
32
  };
24
33
  use temporal_sdk_core_test_utils::{
25
- CoreWfStarter, WorkflowHandleExt, history_from_proto_binary, replay_sdk_worker,
26
- workflows::la_problem_workflow,
34
+ CoreWfStarter, WorkflowHandleExt, history_from_proto_binary, init_core_replay_preloaded,
35
+ replay_sdk_worker, workflows::la_problem_workflow,
27
36
  };
28
37
  use tokio_util::sync::CancellationToken;
29
38
 
@@ -748,3 +757,154 @@ async fn la_resolve_same_time_as_other_cancel() {
748
757
  .await
749
758
  .unwrap();
750
759
  }
760
+
761
+ #[rstest::rstest]
762
+ #[case(200, 0)]
763
+ #[case(200, 2000)]
764
+ #[case(2000, 0)]
765
+ #[case(2000, 2000)]
766
+ #[tokio::test]
767
+ async fn long_local_activity_with_update(
768
+ #[context] ctx: Context,
769
+ #[case] update_interval_ms: u64,
770
+ #[case] update_inner_timer: u64,
771
+ ) {
772
+ let wf_name = format!("{}-{}", ctx.name, ctx.case.unwrap());
773
+ let mut starter = CoreWfStarter::new(&wf_name);
774
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
775
+ let mut worker = starter.worker().await;
776
+ let client = starter.get_client().await;
777
+
778
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
779
+ let update_counter = Arc::new(AtomicUsize::new(1));
780
+ let uc = update_counter.clone();
781
+ ctx.update_handler(
782
+ "update",
783
+ |_: &_, _: ()| Ok(()),
784
+ move |u: UpdateContext, _: ()| {
785
+ let uc = uc.clone();
786
+ async move {
787
+ if update_inner_timer != 0 {
788
+ u.wf_ctx
789
+ .timer(Duration::from_millis(update_inner_timer))
790
+ .await;
791
+ }
792
+ uc.fetch_add(1, Ordering::Relaxed);
793
+ Ok(())
794
+ }
795
+ },
796
+ );
797
+ ctx.local_activity(LocalActivityOptions {
798
+ activity_type: "delay".to_string(),
799
+ input: "hi".as_json_payload().expect("serializes fine"),
800
+ ..Default::default()
801
+ })
802
+ .await;
803
+ update_counter.load(Ordering::Relaxed);
804
+ Ok(().into())
805
+ });
806
+ worker.register_activity("delay", |_: ActContext, _: String| async {
807
+ tokio::time::sleep(Duration::from_secs(6)).await;
808
+ Ok(())
809
+ });
810
+
811
+ let handle = starter
812
+ .start_with_worker(wf_name.clone(), &mut worker)
813
+ .await;
814
+
815
+ let wf_id = starter.get_task_queue().to_string();
816
+ let update = async {
817
+ loop {
818
+ tokio::time::sleep(Duration::from_millis(update_interval_ms)).await;
819
+ let _ = client
820
+ .update_workflow_execution(
821
+ wf_id.clone(),
822
+ "".to_string(),
823
+ "update".to_string(),
824
+ WaitPolicy {
825
+ lifecycle_stage: UpdateWorkflowExecutionLifecycleStage::Completed as i32,
826
+ },
827
+ [().as_json_payload().unwrap()].into_payloads(),
828
+ )
829
+ .await;
830
+ }
831
+ };
832
+ let runner = async {
833
+ worker.run_until_done().await.unwrap();
834
+ };
835
+ tokio::select!(_ = update => {}, _ = runner => {});
836
+ let res = handle
837
+ .get_workflow_result(Default::default())
838
+ .await
839
+ .unwrap()
840
+ .unwrap_success();
841
+ let replay_res = handle
842
+ .fetch_history_and_replay(worker.inner_mut())
843
+ .await
844
+ .unwrap();
845
+ assert_eq!(res[0], replay_res.unwrap());
846
+
847
+ // Load histories from pre-fix version and ensure compat
848
+ let replay_worker = init_core_replay_preloaded(
849
+ starter.get_task_queue(),
850
+ [HistoryForReplay::new(
851
+ history_from_proto_binary(&format!("histories/{wf_name}_history.bin"))
852
+ .await
853
+ .unwrap(),
854
+ "fake".to_owned(),
855
+ )],
856
+ );
857
+ let inner_worker = worker.inner_mut();
858
+ inner_worker.with_new_core_worker(replay_worker);
859
+ inner_worker.set_worker_interceptor(FailOnNondeterminismInterceptor {});
860
+ inner_worker.run().await.unwrap();
861
+ }
862
+
863
+ #[tokio::test]
864
+ async fn local_activity_with_heartbeat_only_causes_one_wakeup() {
865
+ let wf_name = "local_activity_with_heartbeat_only_causes_one_wakeup";
866
+ let mut starter = CoreWfStarter::new(wf_name);
867
+ starter.workflow_options.task_timeout = Some(Duration::from_secs(1));
868
+ let mut worker = starter.worker().await;
869
+
870
+ worker.register_wf(wf_name.to_owned(), move |ctx: WfContext| async move {
871
+ let mut wakeup_counter = 1;
872
+ let la_resolved = AtomicBool::new(false);
873
+ tokio::join!(
874
+ async {
875
+ ctx.local_activity(LocalActivityOptions {
876
+ activity_type: "delay".to_string(),
877
+ input: "hi".as_json_payload().expect("serializes fine"),
878
+ ..Default::default()
879
+ })
880
+ .await;
881
+ la_resolved.store(true, Ordering::Relaxed);
882
+ },
883
+ async {
884
+ ctx.wait_condition(|| {
885
+ wakeup_counter += 1;
886
+ la_resolved.load(Ordering::Relaxed)
887
+ })
888
+ .await;
889
+ }
890
+ );
891
+ Ok(().into())
892
+ });
893
+ worker.register_activity("delay", |_: ActContext, _: String| async {
894
+ tokio::time::sleep(Duration::from_secs(6)).await;
895
+ Ok(())
896
+ });
897
+
898
+ let handle = starter.start_with_worker(wf_name, &mut worker).await;
899
+ worker.run_until_done().await.unwrap();
900
+ let res = handle
901
+ .get_workflow_result(Default::default())
902
+ .await
903
+ .unwrap()
904
+ .unwrap_success();
905
+ let replay_res = handle
906
+ .fetch_history_and_replay(worker.inner_mut())
907
+ .await
908
+ .unwrap();
909
+ assert_eq!(res[0], replay_res.unwrap());
910
+ }