@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,12 +1,34 @@
1
- use crate::integ_tests::activity_functions::echo;
1
+ use crate::{
2
+ common::{
3
+ CoreWfStarter, INTEG_CLIENT_NAME, INTEG_CLIENT_VERSION, get_integ_server_options,
4
+ init_core_and_create_wf, init_integ_telem, integ_dev_server_config, integ_worker_config,
5
+ },
6
+ integ_tests::activity_functions::echo,
7
+ };
2
8
  use assert_matches::assert_matches;
3
- use std::{sync::Arc, time::Duration};
9
+ use futures_util::{FutureExt, StreamExt, future::join_all};
10
+ use std::{
11
+ process::Stdio,
12
+ sync::{
13
+ Arc, Mutex,
14
+ atomic::{AtomicBool, Ordering},
15
+ },
16
+ time::Duration,
17
+ };
4
18
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
5
19
  use temporal_sdk::{ActivityOptions, WfContext};
6
20
  use temporal_sdk_core::{
7
- ClientOptionsBuilder, ephemeral_server::TemporalDevServerConfigBuilder, init_worker,
21
+ ClientOptionsBuilder, CoreRuntime,
22
+ ephemeral_server::{TemporalDevServerConfigBuilder, default_cached_download},
23
+ init_worker,
24
+ telemetry::CoreLogStreamConsumer,
25
+ test_help::{NAMESPACE, WorkerTestHelpers, drain_pollers_and_shutdown},
26
+ };
27
+ use temporal_sdk_core_api::{
28
+ Worker,
29
+ telemetry::{Logger, TelemetryOptionsBuilder},
30
+ worker::PollerBehavior,
8
31
  };
9
- use temporal_sdk_core_api::{Worker, worker::PollerBehavior};
10
32
  use temporal_sdk_core_protos::{
11
33
  coresdk::{
12
34
  AsJsonPayloadExt, IntoCompletion,
@@ -15,13 +37,11 @@ use temporal_sdk_core_protos::{
15
37
  workflow_commands::{ActivityCancellationType, RequestCancelActivity, StartTimer},
16
38
  workflow_completion::WorkflowActivationCompletion,
17
39
  },
40
+ prost_dur,
18
41
  temporal::api::enums::v1::EventType,
42
+ test_utils::schedule_activity_cmd,
19
43
  };
20
- use temporal_sdk_core_test_utils::{
21
- CoreWfStarter, WorkerTestHelpers, default_cached_download, drain_pollers_and_shutdown,
22
- init_core_and_create_wf, init_integ_telem, integ_worker_config, schedule_activity_cmd,
23
- };
24
- use tokio::time::timeout;
44
+ use tokio::{sync::Notify, time::timeout};
25
45
  use tracing::info;
26
46
  use url::Url;
27
47
 
@@ -115,101 +135,117 @@ async fn switching_worker_client_changes_poll() {
115
135
  ])
116
136
  .build()
117
137
  .unwrap();
118
- let mut server1 = server_config.start_server().await.unwrap();
119
- let mut server2 = server_config.start_server().await.unwrap();
120
-
121
- // Connect clients to both servers
122
- info!("Connecting clients");
123
- let mut client_common_config = ClientOptionsBuilder::default();
124
- client_common_config
125
- .identity("integ_tester".to_owned())
126
- .client_name("temporal-core".to_owned())
127
- .client_version("0.1.0".to_owned());
128
- let client1 = client_common_config
129
- .clone()
130
- .target_url(Url::parse(&format!("http://{}", server1.target)).unwrap())
131
- .build()
132
- .unwrap()
133
- .connect("default", None)
138
+ let mut server1 = server_config
139
+ .start_server_with_output(Stdio::null(), Stdio::null())
134
140
  .await
135
141
  .unwrap();
136
- let client2 = client_common_config
137
- .clone()
138
- .target_url(Url::parse(&format!("http://{}", server2.target)).unwrap())
139
- .build()
140
- .unwrap()
141
- .connect("default", None)
142
+ let mut server2 = server_config
143
+ .start_server_with_output(Stdio::null(), Stdio::null())
142
144
  .await
143
145
  .unwrap();
144
146
 
145
- // Start a workflow on both servers
146
- info!("Starting workflows");
147
- let wf1 = client1
148
- .start_workflow(
149
- vec![],
150
- "my-task-queue".to_owned(),
151
- "my-workflow-1".to_owned(),
152
- "my-workflow-type".to_owned(),
153
- None,
154
- WorkflowOptions::default(),
155
- )
156
- .await
157
- .unwrap();
158
- let wf2 = client2
159
- .start_workflow(
160
- vec![],
161
- "my-task-queue".to_owned(),
162
- "my-workflow-2".to_owned(),
163
- "my-workflow-type".to_owned(),
164
- None,
165
- WorkflowOptions::default(),
147
+ let result = std::panic::AssertUnwindSafe(async {
148
+ // Connect clients to both servers
149
+ info!("Connecting clients");
150
+ let mut client_common_config = ClientOptionsBuilder::default();
151
+ client_common_config
152
+ .identity("integ_tester".to_owned())
153
+ .client_name("temporal-core".to_owned())
154
+ .client_version("0.1.0".to_owned());
155
+ let client1 = client_common_config
156
+ .clone()
157
+ .target_url(Url::parse(&format!("http://{}", server1.target)).unwrap())
158
+ .build()
159
+ .unwrap()
160
+ .connect("default", None)
161
+ .await
162
+ .unwrap();
163
+ let client2 = client_common_config
164
+ .clone()
165
+ .target_url(Url::parse(&format!("http://{}", server2.target)).unwrap())
166
+ .build()
167
+ .unwrap()
168
+ .connect("default", None)
169
+ .await
170
+ .unwrap();
171
+
172
+ // Start a workflow on both servers
173
+ info!("Starting workflows");
174
+ let wf1 = client1
175
+ .start_workflow(
176
+ vec![],
177
+ "my-task-queue".to_owned(),
178
+ "my-workflow-1".to_owned(),
179
+ "my-workflow-type".to_owned(),
180
+ None,
181
+ WorkflowOptions::default(),
182
+ )
183
+ .await
184
+ .unwrap();
185
+ let wf2 = client2
186
+ .start_workflow(
187
+ vec![],
188
+ "my-task-queue".to_owned(),
189
+ "my-workflow-2".to_owned(),
190
+ "my-workflow-type".to_owned(),
191
+ None,
192
+ WorkflowOptions::default(),
193
+ )
194
+ .await
195
+ .unwrap();
196
+
197
+ // Create a worker only on the first server
198
+ let worker = init_worker(
199
+ init_integ_telem().unwrap(),
200
+ integ_worker_config("my-task-queue")
201
+ // We want a cache so we don't get extra remove-job activations
202
+ .max_cached_workflows(100_usize)
203
+ .build()
204
+ .unwrap(),
205
+ client1.clone(),
166
206
  )
167
- .await
168
207
  .unwrap();
169
208
 
170
- // Create a worker only on the first server
171
- let worker = init_worker(
172
- init_integ_telem().unwrap(),
173
- integ_worker_config("my-task-queue")
174
- // We want a cache so we don't get extra remove-job activations
175
- .max_cached_workflows(100_usize)
176
- .build()
177
- .unwrap(),
178
- client1.clone(),
179
- )
180
- .unwrap();
209
+ // Poll for first task, confirm it's first wf, complete, and wait for complete
210
+ info!("Doing initial poll");
211
+ let act1 = worker.poll_workflow_activation().await.unwrap();
212
+ assert_eq!(wf1.run_id, act1.run_id);
213
+ worker.complete_execution(&act1.run_id).await;
214
+ worker.handle_eviction().await;
215
+ info!("Waiting on first workflow complete");
216
+ client1
217
+ .get_untyped_workflow_handle("my-workflow-1", wf1.run_id)
218
+ .get_workflow_result(Default::default())
219
+ .await
220
+ .unwrap();
181
221
 
182
- // Poll for first task, confirm it's first wf, complete, and wait for complete
183
- info!("Doing initial poll");
184
- let act1 = worker.poll_workflow_activation().await.unwrap();
185
- assert_eq!(wf1.run_id, act1.run_id);
186
- worker.complete_execution(&act1.run_id).await;
187
- worker.handle_eviction().await;
188
- info!("Waiting on first workflow complete");
189
- client1
190
- .get_untyped_workflow_handle("my-workflow-1", wf1.run_id)
191
- .get_workflow_result(Default::default())
192
- .await
193
- .unwrap();
222
+ // Swap client, poll for next task, confirm it's second wf, and respond w/ empty
223
+ info!("Replacing client and polling again");
224
+ worker.replace_client(client2.get_client().inner().clone());
225
+ let act2 = worker.poll_workflow_activation().await.unwrap();
226
+ assert_eq!(wf2.run_id, act2.run_id);
227
+ worker.complete_execution(&act2.run_id).await;
228
+ worker.handle_eviction().await;
229
+ info!("Waiting on second workflow complete");
230
+ client2
231
+ .get_untyped_workflow_handle("my-workflow-2", wf2.run_id)
232
+ .get_workflow_result(Default::default())
233
+ .await
234
+ .unwrap();
194
235
 
195
- // Swap client, poll for next task, confirm it's second wf, and respond w/ empty
196
- info!("Replacing client and polling again");
197
- worker.replace_client(client2.get_client().inner().clone());
198
- let act2 = worker.poll_workflow_activation().await.unwrap();
199
- assert_eq!(wf2.run_id, act2.run_id);
200
- worker.complete_execution(&act2.run_id).await;
201
- worker.handle_eviction().await;
202
- info!("Waiting on second workflow complete");
203
- client2
204
- .get_untyped_workflow_handle("my-workflow-2", wf2.run_id)
205
- .get_workflow_result(Default::default())
206
- .await
207
- .unwrap();
236
+ // Shutdown workers and servers
237
+ drain_pollers_and_shutdown(&(Arc::new(worker) as Arc<dyn Worker>)).await;
238
+ })
239
+ .catch_unwind()
240
+ .await;
208
241
 
209
- // Shutdown workers and servers
210
- drain_pollers_and_shutdown(&(Arc::new(worker) as Arc<dyn Worker>)).await;
211
- server1.shutdown().await.unwrap();
212
- server2.shutdown().await.unwrap();
242
+ let shutdown_results = join_all([server1.shutdown(), server2.shutdown()]).await;
243
+ if let Err(e) = result {
244
+ std::panic::resume_unwind(e);
245
+ }
246
+ for r in shutdown_results {
247
+ r.unwrap();
248
+ }
213
249
  }
214
250
 
215
251
  #[rstest::rstest]
@@ -292,3 +328,185 @@ async fn small_workflow_slots_and_pollers(#[values(false, true)] use_autoscaling
292
328
  .any(|e| e.event_type() == EventType::WorkflowTaskTimedOut);
293
329
  assert!(!any_task_timeouts);
294
330
  }
331
+
332
+ #[tokio::test]
333
+ async fn replace_client_works_after_polling_failure() {
334
+ let (log_consumer, mut log_rx) = CoreLogStreamConsumer::new(100);
335
+ let telem_opts = TelemetryOptionsBuilder::default()
336
+ .logging(Logger::Push {
337
+ filter: "OFF,temporal_client=DEBUG".into(),
338
+ consumer: Arc::new(log_consumer),
339
+ })
340
+ .build()
341
+ .unwrap();
342
+ let rt = Arc::new(CoreRuntime::new_assume_tokio(telem_opts).unwrap());
343
+
344
+ // Spawning background task to read logs and notify the test when polling failure occurs.
345
+ let look_for_poll_failure_log = Arc::new(AtomicBool::new(false));
346
+ let poll_retry_log_found = Arc::new(Notify::new());
347
+ let log_reader_join_handle = tokio::spawn({
348
+ let look_for_poll_retry_log = look_for_poll_failure_log.clone();
349
+ let poll_retry_log_found = poll_retry_log_found.clone();
350
+ async move {
351
+ let mut enabled = false;
352
+ loop {
353
+ let Some(log) = log_rx.next().await else {
354
+ break;
355
+ };
356
+ if !enabled {
357
+ enabled = look_for_poll_retry_log.load(Ordering::Acquire);
358
+ }
359
+ if enabled
360
+ && (log
361
+ .message
362
+ .starts_with("gRPC call poll_workflow_task_queue failed")
363
+ || log
364
+ .message
365
+ .starts_with("gRPC call poll_workflow_task_queue retried"))
366
+ {
367
+ poll_retry_log_found.notify_one();
368
+ break;
369
+ }
370
+ }
371
+ }
372
+ });
373
+ let abort_handles = Arc::new(Mutex::new(vec![log_reader_join_handle.abort_handle()]));
374
+
375
+ // Starting a second dev server for the worker to connect to initially. Later this server will be shut down
376
+ // and the worker client replaced with a client connected to the main integration test server.
377
+ let initial_server_config = integ_dev_server_config(vec![]).build().unwrap();
378
+ let initial_server = Arc::new(Mutex::new(Some(
379
+ initial_server_config
380
+ .start_server_with_output(Stdio::null(), Stdio::null())
381
+ .await
382
+ .unwrap(),
383
+ )));
384
+
385
+ let result = {
386
+ let initial_server = initial_server.clone();
387
+ let abort_handles = abort_handles.clone();
388
+ std::panic::AssertUnwindSafe(async move {
389
+ let initial_server_target = format!(
390
+ "http://{}",
391
+ initial_server.lock().unwrap().as_ref().unwrap().target
392
+ );
393
+ let client_for_initial_server = ClientOptionsBuilder::default()
394
+ .identity("client_for_initial_server".to_string())
395
+ .target_url(Url::parse(&initial_server_target).unwrap())
396
+ .client_name(INTEG_CLIENT_NAME.to_string())
397
+ .client_version(INTEG_CLIENT_VERSION.to_string())
398
+ .build()
399
+ .unwrap()
400
+ .connect(NAMESPACE, rt.telemetry().get_temporal_metric_meter())
401
+ .await
402
+ .unwrap();
403
+
404
+ let wf_name = "replace_client_works_after_polling_failure";
405
+ let task_queue = format!("{wf_name}_tq");
406
+
407
+ let worker = Arc::new(
408
+ init_worker(
409
+ &rt,
410
+ integ_worker_config(&task_queue)
411
+ .max_cached_workflows(100_usize)
412
+ .build()
413
+ .unwrap(),
414
+ client_for_initial_server.clone(),
415
+ )
416
+ .unwrap(),
417
+ );
418
+
419
+ // Polling the initial server the first time is successful.
420
+ let wf_1 = client_for_initial_server
421
+ .start_workflow(
422
+ vec![],
423
+ task_queue.clone(),
424
+ wf_name.into(),
425
+ wf_name.into(),
426
+ None,
427
+ WorkflowOptions::default(),
428
+ )
429
+ .await
430
+ .unwrap();
431
+ let act_1 =
432
+ tokio::time::timeout(Duration::from_secs(60), worker.poll_workflow_activation())
433
+ .await
434
+ .unwrap()
435
+ .unwrap();
436
+ assert_eq!(act_1.run_id, wf_1.run_id);
437
+
438
+ // Initial server is shut down.
439
+ let mut server = initial_server.lock().unwrap().take().unwrap();
440
+ server.shutdown().await.unwrap();
441
+
442
+ // Start polling in a background task.
443
+ look_for_poll_failure_log.store(true, Ordering::Release);
444
+ let poll_join_handle = tokio::spawn({
445
+ let worker = worker.clone();
446
+ async move { worker.poll_workflow_activation().await }
447
+ });
448
+ abort_handles
449
+ .try_lock()
450
+ .unwrap()
451
+ .push(poll_join_handle.abort_handle());
452
+
453
+ // Wait until polling failure is detected.
454
+ tokio::time::timeout(Duration::from_secs(60), poll_retry_log_found.notified())
455
+ .await
456
+ .unwrap();
457
+
458
+ // Start a new WF on main integration server.
459
+ let client_for_integ_server = get_integ_server_options()
460
+ .connect(NAMESPACE, rt.telemetry().get_temporal_metric_meter())
461
+ .await
462
+ .unwrap();
463
+ let wf_2 = client_for_integ_server
464
+ .start_workflow(
465
+ vec![],
466
+ task_queue,
467
+ wf_name.into(),
468
+ wf_name.into(),
469
+ None,
470
+ WorkflowOptions {
471
+ execution_timeout: Some(Duration::from_secs(60)),
472
+ ..Default::default()
473
+ },
474
+ )
475
+ .await
476
+ .unwrap();
477
+
478
+ // Switch worker over to the main integration server.
479
+ // The polling started on the initial server should complete with a task from the new server.
480
+ worker.replace_client(client_for_integ_server);
481
+ let act_2 = tokio::time::timeout(Duration::from_secs(60), poll_join_handle)
482
+ .await
483
+ .unwrap()
484
+ .unwrap()
485
+ .unwrap();
486
+ assert_eq!(act_2.run_id, wf_2.run_id);
487
+ })
488
+ }
489
+ .catch_unwind()
490
+ .await;
491
+
492
+ // Cleaning up spawned background tasks if they're still running.
493
+ for handle in &*abort_handles.lock().unwrap() {
494
+ handle.abort();
495
+ }
496
+
497
+ // If the test panicked, we may or may not need to shut down the server here.
498
+ // If the test succeeded, the server should always be shut down by this point.
499
+ let server = initial_server.lock().unwrap().take();
500
+ if let Some(mut server) = server {
501
+ let _ = server.shutdown().await;
502
+ assert_matches!(
503
+ result,
504
+ Err(_),
505
+ "Server should have been shut down during the test"
506
+ );
507
+ }
508
+
509
+ if let Err(e) = result {
510
+ std::panic::resume_unwind(e);
511
+ }
512
+ }
@@ -1,18 +1,18 @@
1
+ use crate::common::{CoreWfStarter, init_core_and_create_wf};
1
2
  use assert_matches::assert_matches;
2
3
  use futures_util::{FutureExt, StreamExt, future::join_all, stream::FuturesUnordered};
3
4
  use std::time::{Duration, Instant};
4
5
  use temporal_client::WorkflowClientTrait;
6
+ use temporal_sdk_core::test_help::{WorkerTestHelpers, drain_pollers_and_shutdown};
5
7
  use temporal_sdk_core_protos::{
6
8
  coresdk::{
7
9
  workflow_activation::{WorkflowActivationJob, workflow_activation_job},
8
10
  workflow_commands::{QueryResult, QuerySuccess, StartTimer},
9
11
  workflow_completion::WorkflowActivationCompletion,
10
12
  },
13
+ prost_dur,
11
14
  temporal::api::{failure::v1::Failure, query::v1::WorkflowQuery},
12
- };
13
- use temporal_sdk_core_test_utils::{
14
- CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, init_core_and_create_wf,
15
- start_timer_cmd,
15
+ test_utils::start_timer_cmd,
16
16
  };
17
17
  use tokio::join;
18
18
 
@@ -1,3 +1,6 @@
1
+ use crate::common::{
2
+ CoreWfStarter, WorkflowHandleExt, init_core_and_create_wf, init_core_replay_preloaded,
3
+ };
1
4
  use anyhow::anyhow;
2
5
  use assert_matches::assert_matches;
3
6
  use futures_util::{StreamExt, future, future::join_all};
@@ -12,7 +15,10 @@ use temporal_client::{
12
15
  Client, NamespacedClient, RetryClient, WorkflowClientTrait, WorkflowService,
13
16
  };
14
17
  use temporal_sdk::{ActContext, ActivityOptions, LocalActivityOptions, UpdateContext, WfContext};
15
- use temporal_sdk_core::replay::HistoryForReplay;
18
+ use temporal_sdk_core::{
19
+ replay::HistoryForReplay,
20
+ test_help::{WorkerTestHelpers, drain_pollers_and_shutdown},
21
+ };
16
22
  use temporal_sdk_core_api::Worker;
17
23
  use temporal_sdk_core_protos::{
18
24
  coresdk::{
@@ -26,18 +32,17 @@ use temporal_sdk_core_protos::{
26
32
  },
27
33
  workflow_completion::WorkflowActivationCompletion,
28
34
  },
35
+ prost_dur,
29
36
  temporal::api::{
30
37
  common::v1::WorkflowExecution,
31
38
  enums::v1::{EventType, ResetReapplyType, UpdateWorkflowExecutionLifecycleStage},
32
39
  update::{self, v1::WaitPolicy},
33
40
  workflowservice::v1::ResetWorkflowExecutionRequest,
34
41
  },
35
- };
36
- use temporal_sdk_core_test_utils::{
37
- CoreWfStarter, WorkerTestHelpers, WorkflowHandleExt, drain_pollers_and_shutdown,
38
- init_core_and_create_wf, init_core_replay_preloaded, start_timer_cmd,
42
+ test_utils::start_timer_cmd,
39
43
  };
40
44
  use tokio::{join, sync::Barrier};
45
+ use tonic::IntoRequest;
41
46
  use uuid::Uuid;
42
47
 
43
48
  #[derive(Clone, Copy)]
@@ -112,7 +117,7 @@ async fn reapplied_updates_due_to_reset() {
112
117
  Arc::make_mut(&mut client_mut),
113
118
  #[allow(deprecated)]
114
119
  ResetWorkflowExecutionRequest {
115
- namespace: client.namespace().into(),
120
+ namespace: client.namespace(),
116
121
  workflow_execution: Some(WorkflowExecution {
117
122
  workflow_id: workflow_id.into(),
118
123
  run_id: pre_reset_run_id.clone(),
@@ -121,7 +126,8 @@ async fn reapplied_updates_due_to_reset() {
121
126
  reset_reapply_type: ResetReapplyType::AllEligible as i32,
122
127
  request_id: Uuid::new_v4().to_string(),
123
128
  ..Default::default()
124
- },
129
+ }
130
+ .into_request(),
125
131
  )
126
132
  .await
127
133
  .unwrap()
@@ -1,16 +1,14 @@
1
+ use crate::common::{CoreWfStarter, NAMESPACE, eventually, get_integ_server_options};
1
2
  use assert_matches::assert_matches;
2
3
  use std::{sync::Arc, time::Duration};
3
4
  use temporal_client::{
4
5
  ListClosedFilters, ListOpenFilters, Namespace, RegisterNamespaceOptions, StartTimeFilter,
5
6
  WorkflowClientTrait, WorkflowExecutionFilter,
6
7
  };
8
+ use temporal_sdk_core::test_help::{WorkerTestHelpers, drain_pollers_and_shutdown};
7
9
  use temporal_sdk_core_protos::coresdk::workflow_activation::{
8
10
  WorkflowActivationJob, workflow_activation_job,
9
11
  };
10
- use temporal_sdk_core_test_utils::{
11
- CoreWfStarter, NAMESPACE, WorkerTestHelpers, drain_pollers_and_shutdown,
12
- get_integ_server_options,
13
- };
14
12
  use tokio::time::sleep;
15
13
 
16
14
  #[tokio::test]
@@ -42,11 +40,30 @@ async fn client_list_open_closed_workflow_executions() {
42
40
  workflow_id: wf_name.clone(),
43
41
  run_id: "".to_owned(),
44
42
  });
45
- let open_workflows = client
46
- .list_open_workflow_executions(1, Default::default(), Some(start_time_filter), Some(filter))
47
- .await
48
- .unwrap();
49
- assert_eq!(open_workflows.executions.len(), 1);
43
+ let open_workflows = eventually(
44
+ || async {
45
+ let open_workflows = client
46
+ .list_open_workflow_executions(
47
+ 1,
48
+ Default::default(),
49
+ Some(start_time_filter),
50
+ Some(filter.clone()),
51
+ )
52
+ .await
53
+ .unwrap();
54
+ if open_workflows.executions.len() == 1 {
55
+ Ok(open_workflows)
56
+ } else {
57
+ Err(format!(
58
+ "Expected 1 open workflow, got {}",
59
+ open_workflows.executions.len()
60
+ ))
61
+ }
62
+ },
63
+ Duration::from_secs(5),
64
+ )
65
+ .await
66
+ .unwrap();
50
67
  let workflow = open_workflows.executions[0].clone();
51
68
  assert_eq!(workflow.execution.as_ref().unwrap().workflow_id, wf_name);
52
69