@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.
- package/Cargo.lock +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +207 -108
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +139 -151
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- 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
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
let mock = build_multihist_mock_sg(hists, false, None);
|
|
42
|
-
|
|
43
|
-
let core = &
|
|
44
|
-
|
|
45
|
-
for i in 0..5 {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
163
|
-
let res =
|
|
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!(
|
|
63
|
+
tokio::join!(worker.shutdown(), async {
|
|
168
64
|
// Need to complete task for shutdown to finish
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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 =
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
|
224
|
-
let res =
|
|
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
|
-
|
|
228
|
-
|
|
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![
|
|
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
|
-
|
|
119
|
+
worker.poll_workflow_activation().await.unwrap();
|
|
248
120
|
// Now it's shut down
|
|
249
121
|
assert_matches!(
|
|
250
|
-
|
|
122
|
+
worker.poll_workflow_activation().await.unwrap_err(),
|
|
251
123
|
PollWfError::ShutDown
|
|
252
124
|
);
|
|
253
125
|
});
|
|
254
126
|
}
|
|
255
127
|
|
|
256
|
-
#[
|
|
257
|
-
fn
|
|
128
|
+
#[tokio::test]
|
|
129
|
+
async fn worker_shutdown_during_poll_doesnt_deadlock() {
|
|
258
130
|
let (tx, rx) = watch::channel(false);
|
|
259
|
-
|
|
260
|
-
let
|
|
261
|
-
|
|
262
|
-
let
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
168
|
+
mock.worker_cfg(|w| {
|
|
350
169
|
w.no_remote_activities = true;
|
|
170
|
+
w.max_cached_workflows = 1;
|
|
351
171
|
});
|
|
352
|
-
let
|
|
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
|
-
|
|
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 =
|
|
181
|
+
let res = worker.poll_workflow_activation().await.unwrap();
|
|
366
182
|
// Complete so there's no outstanding WFT and shutdown can finish
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
205
|
+
let core = mock_worker(build_mock_pollers(mh));
|
|
390
206
|
|
|
391
|
-
let res = core.poll_workflow_activation(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
110
|
+
let core = build_fake_worker(wfid, t, &[1]);
|
|
111
111
|
|
|
112
112
|
poll_and_reply(
|
|
113
113
|
&core,
|