@temporalio/core-bridge 0.19.2 → 0.20.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 (125) hide show
  1. package/Cargo.lock +90 -157
  2. package/Cargo.toml +1 -0
  3. package/index.d.ts +11 -27
  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/.buildkite/docker/Dockerfile +1 -1
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.cargo/config.toml +1 -0
  13. package/sdk-core/CODEOWNERS +1 -1
  14. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
  15. package/sdk-core/bridge-ffi/src/lib.rs +311 -315
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
  17. package/sdk-core/client/Cargo.toml +13 -9
  18. package/sdk-core/client/LICENSE.txt +23 -0
  19. package/sdk-core/client/src/lib.rs +286 -174
  20. package/sdk-core/client/src/metrics.rs +86 -12
  21. package/sdk-core/client/src/raw.rs +566 -0
  22. package/sdk-core/client/src/retry.rs +137 -99
  23. package/sdk-core/core/Cargo.toml +15 -10
  24. package/sdk-core/core/LICENSE.txt +23 -0
  25. package/sdk-core/core/benches/workflow_replay.rs +79 -0
  26. package/sdk-core/core/src/abstractions.rs +38 -0
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
  29. package/sdk-core/core/src/core_tests/determinism.rs +24 -12
  30. package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
  31. package/sdk-core/core/src/core_tests/mod.rs +30 -43
  32. package/sdk-core/core/src/core_tests/queries.rs +82 -81
  33. package/sdk-core/core/src/core_tests/workers.rs +111 -296
  34. package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
  35. package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
  36. package/sdk-core/core/src/lib.rs +73 -318
  37. package/sdk-core/core/src/pollers/mod.rs +4 -6
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
  39. package/sdk-core/core/src/protosext/mod.rs +7 -10
  40. package/sdk-core/core/src/replay/mod.rs +11 -150
  41. package/sdk-core/core/src/telemetry/metrics.rs +35 -2
  42. package/sdk-core/core/src/telemetry/mod.rs +49 -16
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
  44. package/sdk-core/core/src/test_help/mod.rs +104 -170
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
  46. package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
  47. package/sdk-core/core/src/worker/activities.rs +23 -16
  48. package/sdk-core/core/src/worker/client/mocks.rs +86 -0
  49. package/sdk-core/core/src/worker/client.rs +209 -0
  50. package/sdk-core/core/src/worker/mod.rs +207 -108
  51. package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
  52. package/sdk-core/core/src/workflow/history_update.rs +107 -24
  53. package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
  54. package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
  55. package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
  56. package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
  57. package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
  58. package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
  59. package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
  60. package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
  61. package/sdk-core/core/src/workflow/mod.rs +13 -1
  62. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
  63. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
  64. package/sdk-core/core-api/Cargo.toml +9 -1
  65. package/sdk-core/core-api/LICENSE.txt +23 -0
  66. package/sdk-core/core-api/src/errors.rs +7 -38
  67. package/sdk-core/core-api/src/lib.rs +44 -52
  68. package/sdk-core/core-api/src/worker.rs +10 -2
  69. package/sdk-core/etc/deps.svg +127 -96
  70. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  73. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  80. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  81. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  84. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  85. package/sdk-core/sdk/Cargo.toml +16 -2
  86. package/sdk-core/sdk/LICENSE.txt +23 -0
  87. package/sdk-core/sdk/src/interceptors.rs +11 -0
  88. package/sdk-core/sdk/src/lib.rs +139 -151
  89. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  90. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  91. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  92. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  93. package/sdk-core/sdk-core-protos/build.rs +1 -0
  94. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  95. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  96. package/sdk-core/test-utils/Cargo.toml +3 -1
  97. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  98. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  99. package/sdk-core/test-utils/src/lib.rs +223 -68
  100. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  101. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  102. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  103. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  104. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  106. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  107. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  108. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
  109. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  110. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  111. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  112. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  113. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  114. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  115. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  116. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  117. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  118. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  119. package/sdk-core/tests/load_tests.rs +9 -6
  120. package/sdk-core/tests/main.rs +43 -10
  121. package/src/conversions.rs +7 -12
  122. package/src/lib.rs +322 -357
  123. package/sdk-core/client/src/mocks.rs +0 -167
  124. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  125. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
@@ -1,23 +1,18 @@
1
1
  use crate::{
2
2
  test_help::{
3
- build_fake_core, build_mock_pollers, build_multihist_mock_sg, canned_histories,
4
- hist_to_poll_resp, mock_core, mock_core_with_opts_no_workers, mock_manual_poller,
5
- register_mock_workers, single_hist_mock_sg, FakeWfResponses, MockPollCfg, MockWorker,
6
- MocksHolder, ResponseType, TEST_Q,
3
+ build_fake_worker, build_mock_pollers, canned_histories, mock_manual_poller, mock_worker,
4
+ MockPollCfg, MockWorker, MocksHolder,
7
5
  },
8
- Core, CoreInitOptionsBuilder, CoreSDK, PollActivityError, PollWfError, WorkerConfigBuilder,
6
+ worker::client::mocks::mock_workflow_client,
7
+ PollActivityError, PollWfError,
9
8
  };
10
9
  use futures::FutureExt;
11
- use rstest::{fixture, rstest};
12
10
  use std::{cell::RefCell, time::Duration};
13
- use temporal_client::mocks::{mock_gateway, mock_manual_gateway};
11
+ use temporal_sdk_core_api::Worker;
14
12
  use temporal_sdk_core_protos::{
15
13
  coresdk::{
16
14
  workflow_activation::workflow_activation_job,
17
- workflow_commands::{
18
- workflow_command, ActivityCancellationType, CompleteWorkflowExecution,
19
- RequestCancelActivity, ScheduleActivity, StartTimer,
20
- },
15
+ workflow_commands::{workflow_command, CompleteWorkflowExecution, StartTimer},
21
16
  workflow_completion::WorkflowActivationCompletion,
22
17
  },
23
18
  temporal::api::workflowservice::v1::RespondWorkflowTaskCompletedResponse,
@@ -27,368 +22,189 @@ use tokio::sync::{watch, Barrier};
27
22
 
28
23
  #[tokio::test]
29
24
  async fn multi_workers() {
25
+ // TODO: Turn this into a test with multiple independent workers
30
26
  // Make histories for 5 different workflows on 5 different task queues
31
- let hists = (0..5).into_iter().map(|i| {
32
- let wf_id = format!("fake-wf-{}", i);
33
- let hist = canned_histories::single_timer("1");
34
- FakeWfResponses {
35
- wf_id,
36
- hist,
37
- response_batches: vec![1.into(), 2.into()],
38
- task_q: format!("q-{}", i),
39
- }
40
- });
41
- let mock = build_multihist_mock_sg(hists, false, None);
42
-
43
- let core = &mock_core(mock);
44
-
45
- for i in 0..5 {
46
- let tq = format!("q-{}", i);
47
- let res = core.poll_workflow_activation(&tq).await.unwrap();
48
- assert_matches!(
49
- res.jobs[0].variant,
50
- Some(workflow_activation_job::Variant::StartWorkflow(_))
51
- );
52
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(tq, res.run_id))
53
- .await
54
- .unwrap();
55
- }
56
- core.shutdown().await;
57
- }
58
-
59
- #[tokio::test]
60
- async fn no_worker_for_queue_error_returned_properly() {
61
- let t = canned_histories::single_timer("1");
62
- // Empty batches to specify 0 calls to poll expectation
63
- let core = build_fake_core("fake_wf_id", t, Vec::<ResponseType>::new());
64
-
65
- core.shutdown_worker(TEST_Q).await;
66
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap_err();
67
- assert_matches!(res, PollWfError::ShutDown);
68
- core.shutdown().await;
69
- }
70
-
71
- #[tokio::test]
72
- async fn shutdown_worker_stays_shutdown_not_no_worker() {
73
- let t = canned_histories::single_timer("1");
74
- // Empty batches to specify 0 calls to poll expectation
75
- let core = build_fake_core("fake_wf_id", t, Vec::<ResponseType>::new());
76
-
77
- let fake_q = "not a registered queue";
78
- let res = core.poll_workflow_activation(fake_q).await.unwrap_err();
79
- assert_matches!(res, PollWfError::NoWorkerForQueue(err_q) => err_q == fake_q);
80
- core.shutdown().await;
81
- }
82
-
83
- #[tokio::test]
84
- async fn worker_double_register_is_err() {
85
- let t = canned_histories::single_timer("1");
86
- let core = build_fake_core("fake_wf_id", t, Vec::<ResponseType>::new());
87
- assert!(core
88
- .register_worker(
89
- WorkerConfigBuilder::default()
90
- .task_queue(TEST_Q)
91
- .max_outstanding_workflow_tasks(2_usize)
92
- .build()
93
- .unwrap(),
94
- )
95
- .is_err());
96
- }
97
-
98
- // Here we're making sure that when a pending activity is generated for a workflow on one task
99
- // queue that it doesn't "leak" over and get returned when lang polls for a different task queue
100
- #[tokio::test]
101
- async fn pending_activities_only_returned_for_their_queue() {
102
- let act_id = 1;
103
- let histmaker = |qname: String| {
104
- let hist =
105
- canned_histories::cancel_scheduled_activity(act_id.to_string().as_str(), "sig-1");
106
- FakeWfResponses {
107
- wf_id: "wf1".to_string(),
108
- hist,
109
- response_batches: vec![1.into(), 2.into()],
110
- task_q: qname,
111
- }
112
- };
113
- let hist_q_1 = histmaker("q-1".to_string());
114
- let hist_q_2 = histmaker("q-2".to_string());
115
- let mock = build_multihist_mock_sg(vec![hist_q_1, hist_q_2], false, None);
116
- let core = &mock_core(mock);
117
-
118
- // Create a pending activation by cancelling a try-cancel activity
119
- let res = core.poll_workflow_activation("q-1").await.unwrap();
120
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
121
- "q-1",
122
- res.run_id,
123
- vec![ScheduleActivity {
124
- seq: act_id,
125
- activity_id: act_id.to_string(),
126
- cancellation_type: ActivityCancellationType::TryCancel as i32,
127
- ..Default::default()
128
- }
129
- .into()],
130
- ))
131
- .await
132
- .unwrap();
133
- let res = core.poll_workflow_activation("q-1").await.unwrap();
134
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
135
- "q-1",
136
- res.run_id,
137
- vec![RequestCancelActivity { seq: act_id }.into()],
138
- ))
139
- .await
140
- .unwrap();
141
- // Poll on the other task queue, verifying we get start workflow
142
- let res = core.poll_workflow_activation("q-2").await.unwrap();
143
- assert_matches!(
144
- res.jobs[0].variant,
145
- Some(workflow_activation_job::Variant::StartWorkflow(_))
146
- );
147
- }
148
-
149
- #[tokio::test]
150
- async fn nonexistent_worker_poll_returns_not_registered() {
151
- let core =
152
- mock_core_with_opts_no_workers(mock_manual_gateway(), CoreInitOptionsBuilder::default());
153
- assert_matches!(
154
- core.poll_workflow_activation(TEST_Q).await.unwrap_err(),
155
- PollWfError::NoWorkerForQueue(_)
156
- );
27
+ // let hists = (0..5).into_iter().map(|i| {
28
+ // let wf_id = format!("fake-wf-{}", i);
29
+ // let hist = canned_histories::single_timer("1");
30
+ // FakeWfResponses {
31
+ // wf_id,
32
+ // hist,
33
+ // response_batches: vec![1.into(), 2.into()],
34
+ // task_q: format!("q-{}", i),
35
+ // }
36
+ // });
37
+ // let mock = build_multihist_mock_sg(hists, false, None);
38
+ //
39
+ // let core = &mock_worker(mock);
40
+ //
41
+ // for i in 0..5 {
42
+ // let tq = format!("q-{}", i);
43
+ // let res = core.poll_workflow_activation().await.unwrap();
44
+ // assert_matches!(
45
+ // res.jobs[0].variant,
46
+ // Some(workflow_activation_job::Variant::StartWorkflow(_))
47
+ // );
48
+ // core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
49
+ // .await
50
+ // .unwrap();
51
+ // }
52
+ // core.shutdown().await;
157
53
  }
158
54
 
159
55
  #[tokio::test]
160
56
  async fn after_shutdown_of_worker_get_shutdown_err() {
161
57
  let t = canned_histories::single_timer("1");
162
- let core = build_fake_core("fake_wf_id", t, &[1]);
163
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
58
+ let worker = build_fake_worker("fake_wf_id", t, &[1]);
59
+ let res = worker.poll_workflow_activation().await.unwrap();
164
60
  assert_eq!(res.jobs.len(), 1);
165
61
  let run_id = res.run_id;
166
62
 
167
- tokio::join!(core.shutdown_worker(TEST_Q), async {
63
+ tokio::join!(worker.shutdown(), async {
168
64
  // Need to complete task for shutdown to finish
169
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
170
- TEST_Q,
171
- run_id.clone(),
172
- workflow_command::Variant::StartTimer(StartTimer {
173
- seq: 1,
174
- start_to_fire_timeout: Some(Duration::from_secs(1).into()),
175
- }),
176
- ))
177
- .await
178
- .unwrap();
65
+ worker
66
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
67
+ run_id.clone(),
68
+ workflow_command::Variant::StartTimer(StartTimer {
69
+ seq: 1,
70
+ start_to_fire_timeout: Some(Duration::from_secs(1).into()),
71
+ }),
72
+ ))
73
+ .await
74
+ .unwrap();
179
75
  // Since non-sticky, one more activation for eviction
180
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
76
+ let res = worker.poll_workflow_activation().await.unwrap();
181
77
  assert_matches!(
182
78
  res.jobs[0].variant,
183
79
  Some(workflow_activation_job::Variant::RemoveFromCache(_))
184
80
  );
185
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(
186
- TEST_Q,
187
- run_id.clone(),
188
- ))
189
- .await
190
- .unwrap();
81
+ worker
82
+ .complete_workflow_activation(WorkflowActivationCompletion::empty(run_id.clone()))
83
+ .await
84
+ .unwrap();
191
85
  assert_matches!(
192
- core.poll_workflow_activation(TEST_Q).await.unwrap_err(),
86
+ worker.poll_workflow_activation().await.unwrap_err(),
193
87
  PollWfError::ShutDown
194
88
  );
195
89
  });
196
90
  }
197
91
 
198
- #[tokio::test]
199
- async fn after_shutdown_of_worker_can_be_reregistered() {
200
- let t = canned_histories::single_timer("1");
201
- let mut core = build_fake_core("fake_wf_id", t.clone(), &[1]);
202
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
203
- assert_eq!(res.jobs.len(), 1);
204
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(TEST_Q, res.run_id))
205
- .await
206
- .unwrap();
207
- core.shutdown_worker(TEST_Q).await;
208
- // Need to recreate mock to re-register worker
209
- let mocks = single_hist_mock_sg("fake_wf_id", t, &[1], mock_gateway(), true);
210
- let pollers = mocks.take_pollers().into_values();
211
- register_mock_workers(&mut core, pollers);
212
- // Worker is replaced and the different mock returns a new wft
213
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
214
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(TEST_Q, res.run_id))
215
- .await
216
- .unwrap();
217
- core.shutdown().await;
218
- }
219
-
220
92
  #[tokio::test]
221
93
  async fn shutdown_worker_can_complete_pending_activation() {
222
94
  let t = canned_histories::single_timer("1");
223
- let core = build_fake_core("fake_wf_id", t, &[2]);
224
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
95
+ let worker = build_fake_worker("fake_wf_id", t, &[2]);
96
+ let res = worker.poll_workflow_activation().await.unwrap();
225
97
  assert_eq!(res.jobs.len(), 1);
226
98
  // Complete the timer, will queue PA
227
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
228
- TEST_Q,
229
- res.run_id,
230
- vec![start_timer_cmd(1, Duration::from_secs(1))],
231
- ))
232
- .await
233
- .unwrap();
234
-
235
- tokio::join!(core.shutdown_worker(TEST_Q), async {
236
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
237
- // The timer fires
238
- assert_eq!(res.jobs.len(), 1);
239
- core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
240
- TEST_Q,
99
+ worker
100
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
241
101
  res.run_id,
242
- vec![CompleteWorkflowExecution::default().into()],
102
+ vec![start_timer_cmd(1, Duration::from_secs(1))],
243
103
  ))
244
104
  .await
245
105
  .unwrap();
106
+
107
+ tokio::join!(worker.shutdown(), async {
108
+ let res = worker.poll_workflow_activation().await.unwrap();
109
+ // The timer fires
110
+ assert_eq!(res.jobs.len(), 1);
111
+ worker
112
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
113
+ res.run_id,
114
+ vec![CompleteWorkflowExecution::default().into()],
115
+ ))
116
+ .await
117
+ .unwrap();
246
118
  // Since non-sticky, one more activation for eviction
247
- core.poll_workflow_activation(TEST_Q).await.unwrap();
119
+ worker.poll_workflow_activation().await.unwrap();
248
120
  // Now it's shut down
249
121
  assert_matches!(
250
- core.poll_workflow_activation(TEST_Q).await.unwrap_err(),
122
+ worker.poll_workflow_activation().await.unwrap_err(),
251
123
  PollWfError::ShutDown
252
124
  );
253
125
  });
254
126
  }
255
127
 
256
- #[fixture]
257
- fn worker_shutdown() -> (CoreSDK, watch::Sender<bool>) {
128
+ #[tokio::test]
129
+ async fn worker_shutdown_during_poll_doesnt_deadlock() {
258
130
  let (tx, rx) = watch::channel(false);
259
-
260
- let mut mock_pollers = vec![];
261
- for i in 1..=2 {
262
- let tq = format!("q{}", i);
263
- let mut mock_poller = mock_manual_poller();
264
- let rx = rx.clone();
265
- let tqc = tq.clone();
266
- mock_poller.expect_poll().returning(move || {
267
- let mut rx = rx.clone();
268
- let tqc = tqc.clone();
269
- async move {
270
- let t = canned_histories::single_timer("1");
271
- // Don't resolve polls until worker shuts down
272
- rx.changed().await.unwrap();
273
- Some(Ok(hist_to_poll_resp(
274
- &t,
275
- "wf".to_string(),
276
- ResponseType::ToTaskNum(1),
277
- tqc,
278
- )))
279
- }
280
- .boxed()
281
- });
282
- mock_pollers.push(MockWorker::new(&tq, Box::from(mock_poller)));
283
- }
284
- let mut mock_gateway = mock_gateway();
285
- mock_gateway
131
+ let mut mock_poller = mock_manual_poller();
132
+ let rx = rx.clone();
133
+ mock_poller.expect_poll().returning(move || {
134
+ let mut rx = rx.clone();
135
+ async move {
136
+ // Don't resolve polls until worker shuts down
137
+ rx.changed().await.unwrap();
138
+ // We don't want to return a real response here because it would get buffered and
139
+ // then we'd have real work to do to be able to finish shutdown.
140
+ Some(Ok(Default::default()))
141
+ }
142
+ .boxed()
143
+ });
144
+ let mw = MockWorker::new(Box::new(mock_poller));
145
+ let mut mock_client = mock_workflow_client();
146
+ mock_client
286
147
  .expect_complete_workflow_task()
287
148
  .returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
288
- (
289
- mock_core(MocksHolder::from_mock_workers(mock_gateway, mock_pollers)),
290
- tx,
291
- )
292
- }
293
-
294
- #[rstest]
295
- #[tokio::test]
296
- async fn worker_shutdown_during_poll_doesnt_deadlock(
297
- worker_shutdown: (CoreSDK, watch::Sender<bool>),
298
- ) {
299
- let (core, tx) = worker_shutdown;
300
- let pollfut = core.poll_workflow_activation("q1");
149
+ let worker = mock_worker(MocksHolder::from_mock_worker(mock_client.into(), mw));
150
+ let pollfut = worker.poll_workflow_activation();
301
151
  let shutdownfut = async {
302
- core.shutdown_worker("q1").await;
152
+ worker.shutdown().await;
303
153
  // Either the send works and unblocks the poll or the poll future is dropped before actually
304
154
  // polling -- either way things worked OK
305
155
  let _ = tx.send(true);
306
156
  };
307
157
  let (pollres, _) = tokio::join!(pollfut, shutdownfut);
308
158
  assert_matches!(pollres.unwrap_err(), PollWfError::ShutDown);
309
- core.shutdown().await;
310
- }
311
-
312
- #[rstest]
313
- #[tokio::test]
314
- async fn worker_shutdown_during_multiple_poll_doesnt_deadlock(
315
- worker_shutdown: (CoreSDK, watch::Sender<bool>),
316
- ) {
317
- let (core, tx) = worker_shutdown;
318
-
319
- let pollfut = async {
320
- assert_matches!(
321
- core.poll_workflow_activation("q1").await.unwrap_err(),
322
- PollWfError::ShutDown
323
- );
324
- };
325
- let poll2fut = async {
326
- let res = core.poll_workflow_activation("q2").await.unwrap();
327
- core.complete_workflow_activation(WorkflowActivationCompletion::empty("q2", res.run_id))
328
- .await
329
- .unwrap();
330
- };
331
- let shutdownfut = async {
332
- core.shutdown_worker("q1").await;
333
- // Will allow both workers to proceed
334
- let _ = tx.send(true);
335
- };
336
- tokio::join!(pollfut, poll2fut, shutdownfut);
337
- core.shutdown().await;
159
+ worker.finalize_shutdown().await;
338
160
  }
339
161
 
340
- #[rstest]
341
162
  #[tokio::test]
342
- async fn can_shutdown_local_act_only_worker_when_act_polling(
343
- #[values(true, false)] whole_core_shutdown: bool,
344
- ) {
163
+ async fn can_shutdown_local_act_only_worker_when_act_polling() {
345
164
  let t = canned_histories::single_timer("1");
346
- let mock = mock_gateway();
165
+ let mock = mock_workflow_client();
347
166
  let mh = MockPollCfg::from_resp_batches("fakeid", t, [1], mock);
348
167
  let mut mock = build_mock_pollers(mh);
349
- mock.worker_cfg(TEST_Q, |w| {
168
+ mock.worker_cfg(|w| {
350
169
  w.no_remote_activities = true;
170
+ w.max_cached_workflows = 1;
351
171
  });
352
- let core = mock_core(mock);
172
+ let worker = mock_worker(mock);
353
173
  let barrier = Barrier::new(2);
354
174
 
355
175
  tokio::join!(
356
176
  async {
357
177
  barrier.wait().await;
358
- if whole_core_shutdown {
359
- core.shutdown().await;
360
- } else {
361
- core.shutdown_worker(TEST_Q).await;
362
- }
178
+ worker.shutdown().await;
363
179
  },
364
180
  async {
365
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
181
+ let res = worker.poll_workflow_activation().await.unwrap();
366
182
  // Complete so there's no outstanding WFT and shutdown can finish
367
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(
368
- TEST_Q, res.run_id,
369
- ))
370
- .await
371
- .unwrap();
183
+ worker
184
+ .complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
185
+ .await
186
+ .unwrap();
372
187
  barrier.wait().await;
373
188
  assert_matches!(
374
- core.poll_activity_task(TEST_Q).await.unwrap_err(),
189
+ worker.poll_activity_task().await.unwrap_err(),
375
190
  PollActivityError::ShutDown
376
191
  );
377
192
  }
378
193
  );
194
+ worker.finalize_shutdown().await;
379
195
  }
380
196
 
381
197
  #[tokio::test]
382
198
  async fn complete_with_task_not_found_during_shutdwn() {
383
199
  let t = canned_histories::single_timer("1");
384
- let mut mock = mock_gateway();
200
+ let mut mock = mock_workflow_client();
385
201
  mock.expect_complete_workflow_task()
386
202
  .times(1)
387
203
  .returning(|_| Err(tonic::Status::not_found("Workflow task not found.")));
388
204
  let mh = MockPollCfg::from_resp_batches("fakeid", t, [1], mock);
389
- let core = mock_core(build_mock_pollers(mh));
205
+ let core = mock_worker(build_mock_pollers(mh));
390
206
 
391
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
207
+ let res = core.poll_workflow_activation().await.unwrap();
392
208
  assert_eq!(res.jobs.len(), 1);
393
209
 
394
210
  let complete_order = RefCell::new(vec![]);
@@ -400,19 +216,18 @@ async fn complete_with_task_not_found_during_shutdwn() {
400
216
  let poll_fut = async {
401
217
  // This should *not* return shutdown, but instead should do nothing until the complete
402
218
  // goes through, at which point it will return the eviction.
403
- let res = core.poll_workflow_activation(TEST_Q).await.unwrap();
219
+ let res = core.poll_workflow_activation().await.unwrap();
404
220
  assert_matches!(
405
221
  res.jobs[0].variant,
406
222
  Some(workflow_activation_job::Variant::RemoveFromCache(_))
407
223
  );
408
- core.complete_workflow_activation(WorkflowActivationCompletion::empty(TEST_Q, res.run_id))
224
+ core.complete_workflow_activation(WorkflowActivationCompletion::empty(res.run_id))
409
225
  .await
410
226
  .unwrap();
411
227
  complete_order.borrow_mut().push(2);
412
228
  };
413
229
  let complete_fut = async {
414
230
  core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
415
- TEST_Q,
416
231
  res.run_id,
417
232
  vec![start_timer_cmd(1, Duration::from_secs(1))],
418
233
  ))
@@ -1,7 +1,7 @@
1
1
  use crate::{
2
2
  job_assert,
3
3
  test_help::{
4
- build_fake_core, canned_histories, gen_assert_and_reply, poll_and_reply, ResponseType,
4
+ build_fake_worker, canned_histories, gen_assert_and_reply, poll_and_reply, ResponseType,
5
5
  },
6
6
  workflow::WorkflowCachingPolicy::NonSticky,
7
7
  };
@@ -45,7 +45,7 @@ async fn timer_then_cancel_req(
45
45
  canned_histories::timer_wf_cancel_req_cancelled(timer_id.as_str())
46
46
  }
47
47
  };
48
- let core = build_fake_core(wfid, t, hist_batches);
48
+ let core = build_fake_worker(wfid, t, hist_batches);
49
49
 
50
50
  let final_cmd = match completion_type {
51
51
  CompletionType::Complete => CompleteWorkflowExecution::default().into(),
@@ -77,7 +77,7 @@ async fn timer_then_cancel_req(
77
77
  async fn timer_then_cancel_req_then_timer_then_cancelled() {
78
78
  let wfid = "fake_wf_id";
79
79
  let t = canned_histories::timer_wf_cancel_req_do_another_timer_then_cancelled();
80
- let core = build_fake_core(wfid, t, [ResponseType::AllHistory]);
80
+ let core = build_fake_worker(wfid, t, [ResponseType::AllHistory]);
81
81
 
82
82
  poll_and_reply(
83
83
  &core,
@@ -107,7 +107,7 @@ async fn timer_then_cancel_req_then_timer_then_cancelled() {
107
107
  async fn immediate_cancel() {
108
108
  let wfid = "fake_wf_id";
109
109
  let t = canned_histories::immediate_wf_cancel();
110
- let core = build_fake_core(wfid, t, &[1]);
110
+ let core = build_fake_worker(wfid, t, &[1]);
111
111
 
112
112
  poll_and_reply(
113
113
  &core,