@temporalio/core-bridge 0.16.4 → 0.18.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.
- package/Cargo.lock +339 -226
- package/Cargo.toml +7 -3
- package/common.js +50 -0
- package/index.d.ts +7 -0
- package/index.js +12 -0
- package/package.json +7 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/{index.node → releases/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/scripts/build.js +10 -50
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
- package/sdk-core/.buildkite/pipeline.yml +2 -0
- package/sdk-core/Cargo.toml +1 -88
- package/sdk-core/README.md +30 -6
- package/sdk-core/bridge-ffi/Cargo.toml +24 -0
- package/sdk-core/bridge-ffi/LICENSE.txt +23 -0
- package/sdk-core/bridge-ffi/build.rs +25 -0
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +216 -0
- package/sdk-core/bridge-ffi/src/lib.rs +829 -0
- package/sdk-core/bridge-ffi/src/wrappers.rs +193 -0
- package/sdk-core/client/Cargo.toml +32 -0
- package/sdk-core/{src/pollers/gateway.rs → client/src/lib.rs} +101 -195
- package/sdk-core/client/src/metrics.rs +89 -0
- package/sdk-core/client/src/mocks.rs +167 -0
- package/sdk-core/{src/pollers → client/src}/retry.rs +172 -14
- package/sdk-core/core/Cargo.toml +96 -0
- package/sdk-core/{src → core/src}/core_tests/activity_tasks.rs +193 -37
- package/sdk-core/{src → core/src}/core_tests/child_workflows.rs +14 -14
- package/sdk-core/{src → core/src}/core_tests/determinism.rs +8 -8
- package/sdk-core/core/src/core_tests/local_activities.rs +328 -0
- package/sdk-core/{src → core/src}/core_tests/mod.rs +6 -9
- package/sdk-core/{src → core/src}/core_tests/queries.rs +54 -54
- package/sdk-core/{src → core/src}/core_tests/replay_flag.rs +8 -12
- package/sdk-core/{src → core/src}/core_tests/workers.rs +120 -33
- package/sdk-core/{src → core/src}/core_tests/workflow_cancels.rs +16 -26
- package/sdk-core/{src → core/src}/core_tests/workflow_tasks.rs +280 -292
- package/sdk-core/core/src/lib.rs +374 -0
- package/sdk-core/{src → core/src}/log_export.rs +3 -27
- package/sdk-core/core/src/pending_activations.rs +162 -0
- package/sdk-core/{src → core/src}/pollers/mod.rs +4 -22
- package/sdk-core/{src → core/src}/pollers/poll_buffer.rs +1 -1
- package/sdk-core/core/src/protosext/mod.rs +396 -0
- package/sdk-core/core/src/replay/mod.rs +210 -0
- package/sdk-core/core/src/retry_logic.rs +144 -0
- package/sdk-core/{src → core/src}/telemetry/metrics.rs +3 -58
- package/sdk-core/{src → core/src}/telemetry/mod.rs +8 -8
- package/sdk-core/{src → core/src}/telemetry/prometheus_server.rs +0 -0
- package/sdk-core/{src → core/src}/test_help/mod.rs +35 -83
- package/sdk-core/{src → core/src}/worker/activities/activity_heartbeat_manager.rs +95 -42
- package/sdk-core/core/src/worker/activities/local_activities.rs +973 -0
- package/sdk-core/{src → core/src}/worker/activities.rs +52 -33
- package/sdk-core/{src → core/src}/worker/dispatcher.rs +8 -6
- package/sdk-core/{src → core/src}/worker/mod.rs +347 -221
- package/sdk-core/core/src/worker/wft_delivery.rs +81 -0
- package/sdk-core/{src → core/src}/workflow/bridge.rs +5 -2
- package/sdk-core/{src → core/src}/workflow/driven_workflow.rs +17 -7
- package/sdk-core/{src → core/src}/workflow/history_update.rs +33 -7
- package/sdk-core/{src → core/src/workflow}/machines/activity_state_machine.rs +26 -26
- package/sdk-core/{src → core/src/workflow}/machines/cancel_external_state_machine.rs +8 -11
- package/sdk-core/{src → core/src/workflow}/machines/cancel_workflow_state_machine.rs +19 -21
- package/sdk-core/{src → core/src/workflow}/machines/child_workflow_state_machine.rs +20 -31
- package/sdk-core/{src → core/src/workflow}/machines/complete_workflow_state_machine.rs +3 -5
- package/sdk-core/{src → core/src/workflow}/machines/continue_as_new_workflow_state_machine.rs +18 -18
- package/sdk-core/{src → core/src/workflow}/machines/fail_workflow_state_machine.rs +5 -6
- package/sdk-core/core/src/workflow/machines/local_activity_state_machine.rs +1451 -0
- package/sdk-core/{src → core/src/workflow}/machines/mod.rs +54 -107
- package/sdk-core/{src → core/src/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
- package/sdk-core/{src → core/src/workflow}/machines/patch_state_machine.rs +29 -30
- package/sdk-core/{src → core/src/workflow}/machines/side_effect_state_machine.rs +0 -0
- package/sdk-core/{src → core/src/workflow}/machines/signal_external_state_machine.rs +17 -19
- package/sdk-core/{src → core/src/workflow}/machines/timer_state_machine.rs +20 -21
- package/sdk-core/{src → core/src/workflow}/machines/transition_coverage.rs +5 -2
- package/sdk-core/{src → core/src/workflow}/machines/upsert_search_attributes_state_machine.rs +0 -0
- package/sdk-core/core/src/workflow/machines/workflow_machines/local_acts.rs +96 -0
- package/sdk-core/{src → core/src/workflow}/machines/workflow_machines.rs +357 -171
- package/sdk-core/{src → core/src/workflow}/machines/workflow_task_state_machine.rs +1 -1
- package/sdk-core/{src → core/src}/workflow/mod.rs +200 -39
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/cache_manager.rs +0 -0
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/concurrency_manager.rs +38 -5
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/mod.rs +317 -103
- package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
- package/sdk-core/{src → core-api/src}/errors.rs +42 -92
- package/sdk-core/core-api/src/lib.rs +158 -0
- package/sdk-core/{src/worker/config.rs → core-api/src/worker.rs} +18 -23
- package/sdk-core/etc/deps.svg +156 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +5 -5
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +3 -5
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -1
- package/sdk-core/histories/fail_wf_task.bin +0 -0
- package/sdk-core/histories/timer_workflow_history.bin +0 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +44 -13
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +19 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +9 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +13 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +14 -7
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +176 -18
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +156 -7
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +135 -104
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +78 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +205 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +61 -0
- package/sdk-core/protos/local/{child_workflow.proto → temporal/sdk/core/child_workflow/child_workflow.proto} +1 -1
- package/sdk-core/protos/local/{common.proto → temporal/sdk/core/common/common.proto} +5 -3
- package/sdk-core/protos/local/{core_interface.proto → temporal/sdk/core/core_interface.proto} +10 -10
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
- package/sdk-core/protos/local/{workflow_activation.proto → temporal/sdk/core/workflow_activation/workflow_activation.proto} +35 -11
- package/sdk-core/protos/local/{workflow_commands.proto → temporal/sdk/core/workflow_commands/workflow_commands.proto} +55 -4
- package/sdk-core/protos/local/{workflow_completion.proto → temporal/sdk/core/workflow_completion/workflow_completion.proto} +3 -3
- package/sdk-core/sdk/Cargo.toml +32 -0
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/conversions.rs +0 -0
- package/sdk-core/sdk/src/lib.rs +699 -0
- package/sdk-core/sdk/src/payload_converter.rs +11 -0
- package/sdk-core/sdk/src/workflow_context/options.rs +180 -0
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_context.rs +201 -124
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_future.rs +63 -30
- package/sdk-core/sdk-core-protos/Cargo.toml +10 -0
- package/sdk-core/sdk-core-protos/build.rs +28 -6
- package/sdk-core/sdk-core-protos/src/constants.rs +7 -0
- package/sdk-core/{src/test_help → sdk-core-protos/src}/history_builder.rs +134 -49
- package/sdk-core/sdk-core-protos/src/history_info.rs +216 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +601 -168
- package/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +32 -0
- package/sdk-core/{src/test_help → test-utils/src}/canned_histories.rs +59 -78
- package/sdk-core/test-utils/src/histfetch.rs +28 -0
- package/sdk-core/{test_utils → test-utils}/src/lib.rs +131 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -7
- package/sdk-core/tests/integ_tests/polling_tests.rs +12 -11
- package/sdk-core/tests/integ_tests/queries_tests.rs +82 -78
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +91 -71
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +3 -4
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -6
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +4 -6
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -4
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +496 -0
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +5 -8
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +125 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +7 -13
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +33 -5
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +12 -16
- package/sdk-core/tests/integ_tests/workflow_tests.rs +85 -82
- package/sdk-core/tests/load_tests.rs +6 -6
- package/sdk-core/tests/main.rs +2 -2
- package/src/conversions.rs +24 -21
- package/src/errors.rs +8 -0
- package/src/lib.rs +323 -211
- package/sdk-core/protos/local/activity_result.proto +0 -46
- package/sdk-core/protos/local/activity_task.proto +0 -66
- package/sdk-core/src/core_tests/retry.rs +0 -147
- package/sdk-core/src/lib.rs +0 -403
- package/sdk-core/src/machines/local_activity_state_machine.rs +0 -117
- package/sdk-core/src/pending_activations.rs +0 -249
- package/sdk-core/src/protosext/mod.rs +0 -160
- package/sdk-core/src/prototype_rust_sdk.rs +0 -412
- package/sdk-core/src/task_token.rs +0 -20
- package/sdk-core/src/test_help/history_info.rs +0 -157
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
job_assert,
|
|
3
|
-
pollers::{MockManualGateway, MockServerGatewayApis},
|
|
4
3
|
test_help::{
|
|
5
|
-
build_fake_core, canned_histories,
|
|
4
|
+
build_fake_core, canned_histories, gen_assert_and_reply, mock_core,
|
|
6
5
|
mock_core_with_opts_no_workers, mock_manual_poller, mock_poller, mock_poller_from_resps,
|
|
7
6
|
poll_and_reply, MockWorker, MocksHolder, TEST_Q,
|
|
8
7
|
},
|
|
@@ -11,31 +10,35 @@ use crate::{
|
|
|
11
10
|
};
|
|
12
11
|
use futures::FutureExt;
|
|
13
12
|
use std::{
|
|
13
|
+
cell::RefCell,
|
|
14
14
|
collections::{hash_map::Entry, HashMap, VecDeque},
|
|
15
|
+
rc::Rc,
|
|
15
16
|
sync::{
|
|
16
17
|
atomic::{AtomicUsize, Ordering},
|
|
17
18
|
Arc,
|
|
18
19
|
},
|
|
19
20
|
time::Duration,
|
|
20
21
|
};
|
|
22
|
+
use temporal_client::mocks::{fake_sg_opts, mock_gateway, mock_manual_gateway};
|
|
21
23
|
use temporal_sdk_core_protos::{
|
|
22
24
|
coresdk::{
|
|
23
|
-
activity_result::{
|
|
25
|
+
activity_result::{activity_resolution, ActivityExecutionResult, ActivityResolution},
|
|
24
26
|
activity_task::activity_task,
|
|
25
|
-
workflow_activation::{
|
|
27
|
+
workflow_activation::{workflow_activation_job, ResolveActivity, WorkflowActivationJob},
|
|
26
28
|
workflow_commands::{
|
|
27
29
|
ActivityCancellationType, CompleteWorkflowExecution, RequestCancelActivity,
|
|
28
|
-
ScheduleActivity,
|
|
30
|
+
ScheduleActivity,
|
|
29
31
|
},
|
|
30
32
|
ActivityTaskCompletion,
|
|
31
33
|
},
|
|
32
34
|
temporal::api::workflowservice::v1::{
|
|
33
35
|
PollActivityTaskQueueResponse, RecordActivityTaskHeartbeatResponse,
|
|
34
|
-
RespondActivityTaskCompletedResponse,
|
|
36
|
+
RespondActivityTaskCanceledResponse, RespondActivityTaskCompletedResponse,
|
|
37
|
+
RespondActivityTaskFailedResponse,
|
|
35
38
|
},
|
|
36
39
|
};
|
|
37
|
-
use
|
|
38
|
-
use tokio::{sync::Notify, time::sleep};
|
|
40
|
+
use temporal_sdk_core_test_utils::{fanout_tasks, start_timer_cmd};
|
|
41
|
+
use tokio::{join, sync::Notify, time::sleep};
|
|
39
42
|
|
|
40
43
|
#[tokio::test]
|
|
41
44
|
async fn max_activities_respected() {
|
|
@@ -57,7 +60,7 @@ async fn max_activities_respected() {
|
|
|
57
60
|
..Default::default()
|
|
58
61
|
},
|
|
59
62
|
]);
|
|
60
|
-
let mut mock_gateway =
|
|
63
|
+
let mut mock_gateway = mock_gateway();
|
|
61
64
|
mock_gateway
|
|
62
65
|
.expect_poll_activity_task()
|
|
63
66
|
.times(3)
|
|
@@ -80,7 +83,6 @@ async fn max_activities_respected() {
|
|
|
80
83
|
.build()
|
|
81
84
|
.unwrap(),
|
|
82
85
|
)
|
|
83
|
-
.await
|
|
84
86
|
.unwrap();
|
|
85
87
|
|
|
86
88
|
// We allow two outstanding activities, therefore first two polls should return right away
|
|
@@ -93,7 +95,7 @@ async fn max_activities_respected() {
|
|
|
93
95
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
94
96
|
task_token: r1.task_token,
|
|
95
97
|
task_queue: TEST_Q.to_string(),
|
|
96
|
-
result: Some(
|
|
98
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into()))
|
|
97
99
|
}).await.unwrap();
|
|
98
100
|
last_finisher.store(1, Ordering::SeqCst);
|
|
99
101
|
},
|
|
@@ -108,7 +110,7 @@ async fn max_activities_respected() {
|
|
|
108
110
|
|
|
109
111
|
#[tokio::test]
|
|
110
112
|
async fn activity_not_found_returns_ok() {
|
|
111
|
-
let mut mock_gateway =
|
|
113
|
+
let mut mock_gateway = mock_gateway();
|
|
112
114
|
// Mock won't even be called, since we weren't tracking activity
|
|
113
115
|
mock_gateway.expect_complete_activity_task().times(0);
|
|
114
116
|
|
|
@@ -121,7 +123,7 @@ async fn activity_not_found_returns_ok() {
|
|
|
121
123
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
122
124
|
task_token: vec![1],
|
|
123
125
|
task_queue: TEST_Q.to_string(),
|
|
124
|
-
result: Some(
|
|
126
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
125
127
|
})
|
|
126
128
|
.await
|
|
127
129
|
.unwrap();
|
|
@@ -130,7 +132,7 @@ async fn activity_not_found_returns_ok() {
|
|
|
130
132
|
|
|
131
133
|
#[tokio::test]
|
|
132
134
|
async fn heartbeats_report_cancels_only_once() {
|
|
133
|
-
let mut mock_gateway =
|
|
135
|
+
let mut mock_gateway = mock_gateway();
|
|
134
136
|
mock_gateway
|
|
135
137
|
.expect_record_activity_heartbeat()
|
|
136
138
|
.times(2)
|
|
@@ -139,6 +141,14 @@ async fn heartbeats_report_cancels_only_once() {
|
|
|
139
141
|
cancel_requested: true,
|
|
140
142
|
})
|
|
141
143
|
});
|
|
144
|
+
mock_gateway
|
|
145
|
+
.expect_complete_activity_task()
|
|
146
|
+
.times(1)
|
|
147
|
+
.returning(|_, _| Ok(RespondActivityTaskCompletedResponse::default()));
|
|
148
|
+
mock_gateway
|
|
149
|
+
.expect_cancel_activity_task()
|
|
150
|
+
.times(1)
|
|
151
|
+
.returning(|_, _| Ok(RespondActivityTaskCanceledResponse::default()));
|
|
142
152
|
|
|
143
153
|
let core = mock_core(MocksHolder::from_gateway_with_responses(
|
|
144
154
|
mock_gateway,
|
|
@@ -181,22 +191,39 @@ async fn heartbeats_report_cancels_only_once() {
|
|
|
181
191
|
// Allow heartbeat delay to elapse
|
|
182
192
|
sleep(Duration::from_millis(10)).await;
|
|
183
193
|
core.record_activity_heartbeat(ActivityHeartbeat {
|
|
184
|
-
task_token: act.task_token,
|
|
194
|
+
task_token: act.task_token.clone(),
|
|
185
195
|
task_queue: TEST_Q.to_string(),
|
|
186
196
|
details: vec![vec![1_u8, 2, 3].into()],
|
|
187
197
|
});
|
|
198
|
+
// Wait delay again to flush heartbeat
|
|
188
199
|
sleep(Duration::from_millis(10)).await;
|
|
200
|
+
// Now complete it as cancelled
|
|
201
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
202
|
+
task_token: act.task_token,
|
|
203
|
+
task_queue: TEST_Q.to_string(),
|
|
204
|
+
result: Some(ActivityExecutionResult::cancel_from_details(None)),
|
|
205
|
+
})
|
|
206
|
+
.await
|
|
207
|
+
.unwrap();
|
|
189
208
|
// Since cancels always come before new tasks, if we get a new non-cancel task, we did not
|
|
190
209
|
// double-issue cancels.
|
|
191
210
|
let act = core.poll_activity_task(TEST_Q).await.unwrap();
|
|
192
211
|
assert_matches!(
|
|
193
|
-
act,
|
|
212
|
+
&act,
|
|
194
213
|
ActivityTask {
|
|
195
214
|
task_token,
|
|
196
215
|
variant: Some(activity_task::Variant::Start(_)),
|
|
197
216
|
..
|
|
198
|
-
} => { task_token ==
|
|
217
|
+
} => { task_token == &[2] }
|
|
199
218
|
);
|
|
219
|
+
// Complete it so shutdown goes through
|
|
220
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
221
|
+
task_token: act.task_token,
|
|
222
|
+
task_queue: TEST_Q.to_string(),
|
|
223
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
224
|
+
})
|
|
225
|
+
.await
|
|
226
|
+
.unwrap();
|
|
200
227
|
core.shutdown().await;
|
|
201
228
|
}
|
|
202
229
|
|
|
@@ -223,7 +250,7 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
223
250
|
.times(2)
|
|
224
251
|
.returning(move || poll_resps.pop_front().unwrap());
|
|
225
252
|
|
|
226
|
-
let mut mock_gateway =
|
|
253
|
+
let mut mock_gateway = mock_manual_gateway();
|
|
227
254
|
mock_gateway
|
|
228
255
|
.expect_record_activity_heartbeat()
|
|
229
256
|
.times(1)
|
|
@@ -235,6 +262,10 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
235
262
|
}
|
|
236
263
|
.boxed()
|
|
237
264
|
});
|
|
265
|
+
mock_gateway
|
|
266
|
+
.expect_complete_activity_task()
|
|
267
|
+
.times(1)
|
|
268
|
+
.returning(|_, _| async { Ok(RespondActivityTaskCompletedResponse::default()) }.boxed());
|
|
238
269
|
|
|
239
270
|
let mock_worker = MockWorker {
|
|
240
271
|
act_poller: Some(Box::from(mock_poller)),
|
|
@@ -256,7 +287,15 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
256
287
|
last_finisher.store(1, Ordering::SeqCst);
|
|
257
288
|
},
|
|
258
289
|
async {
|
|
259
|
-
core.poll_activity_task(TEST_Q).await.unwrap();
|
|
290
|
+
let act = core.poll_activity_task(TEST_Q).await.unwrap();
|
|
291
|
+
// Must complete this activity for shutdown to finish
|
|
292
|
+
core.complete_activity_task(
|
|
293
|
+
ActivityTaskCompletion {
|
|
294
|
+
task_token: act.task_token,
|
|
295
|
+
task_queue: TEST_Q.to_string(),
|
|
296
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
297
|
+
}
|
|
298
|
+
).await.unwrap();
|
|
260
299
|
last_finisher.store(2, Ordering::SeqCst);
|
|
261
300
|
}
|
|
262
301
|
};
|
|
@@ -267,7 +306,7 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
267
306
|
|
|
268
307
|
#[tokio::test]
|
|
269
308
|
async fn activity_poll_timeout_retries() {
|
|
270
|
-
let mock_gateway =
|
|
309
|
+
let mock_gateway = mock_gateway();
|
|
271
310
|
let mut calls = 0;
|
|
272
311
|
let mut mock_act_poller = mock_poller();
|
|
273
312
|
mock_act_poller.expect_poll().times(3).returning(move || {
|
|
@@ -296,7 +335,7 @@ async fn many_concurrent_heartbeat_cancels() {
|
|
|
296
335
|
// them after a few successful heartbeats
|
|
297
336
|
const CONCURRENCY_NUM: usize = 5;
|
|
298
337
|
|
|
299
|
-
let mut mock_gateway =
|
|
338
|
+
let mut mock_gateway = mock_manual_gateway();
|
|
300
339
|
let mut poll_resps = VecDeque::from(
|
|
301
340
|
(0..CONCURRENCY_NUM)
|
|
302
341
|
.map(|i| {
|
|
@@ -362,7 +401,6 @@ async fn many_concurrent_heartbeat_cancels() {
|
|
|
362
401
|
.build()
|
|
363
402
|
.unwrap(),
|
|
364
403
|
)
|
|
365
|
-
.await
|
|
366
404
|
.unwrap();
|
|
367
405
|
|
|
368
406
|
// Poll all activities first so they are registered
|
|
@@ -397,7 +435,7 @@ async fn many_concurrent_heartbeat_cancels() {
|
|
|
397
435
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
398
436
|
task_token: r.task_token.clone(),
|
|
399
437
|
task_queue: TEST_Q.to_string(),
|
|
400
|
-
result: Some(
|
|
438
|
+
result: Some(ActivityExecutionResult::cancel_from_details(None)),
|
|
401
439
|
})
|
|
402
440
|
.await
|
|
403
441
|
.unwrap();
|
|
@@ -418,7 +456,7 @@ async fn activity_timeout_no_double_resolve() {
|
|
|
418
456
|
NonSticky,
|
|
419
457
|
&[
|
|
420
458
|
gen_assert_and_reply(
|
|
421
|
-
&job_assert!(
|
|
459
|
+
&job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
422
460
|
vec![ScheduleActivity {
|
|
423
461
|
seq: activity_id,
|
|
424
462
|
activity_id: activity_id.to_string(),
|
|
@@ -428,21 +466,17 @@ async fn activity_timeout_no_double_resolve() {
|
|
|
428
466
|
.into()],
|
|
429
467
|
),
|
|
430
468
|
gen_assert_and_reply(
|
|
431
|
-
&job_assert!(
|
|
469
|
+
&job_assert!(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
432
470
|
vec![
|
|
433
471
|
RequestCancelActivity { seq: activity_id }.into(),
|
|
434
|
-
|
|
435
|
-
seq: 2,
|
|
436
|
-
..Default::default()
|
|
437
|
-
}
|
|
438
|
-
.into(),
|
|
472
|
+
start_timer_cmd(2, Duration::from_secs(1)),
|
|
439
473
|
],
|
|
440
474
|
),
|
|
441
475
|
gen_assert_and_reply(
|
|
442
|
-
&job_assert!(
|
|
476
|
+
&job_assert!(workflow_activation_job::Variant::ResolveActivity(
|
|
443
477
|
ResolveActivity {
|
|
444
|
-
result: Some(
|
|
445
|
-
status: Some(
|
|
478
|
+
result: Some(ActivityResolution {
|
|
479
|
+
status: Some(activity_resolution::Status::Cancelled(..)),
|
|
446
480
|
}),
|
|
447
481
|
..
|
|
448
482
|
}
|
|
@@ -451,8 +485,8 @@ async fn activity_timeout_no_double_resolve() {
|
|
|
451
485
|
),
|
|
452
486
|
gen_assert_and_reply(
|
|
453
487
|
&job_assert!(
|
|
454
|
-
|
|
455
|
-
|
|
488
|
+
workflow_activation_job::Variant::SignalWorkflow(_),
|
|
489
|
+
workflow_activation_job::Variant::FireTimer(_)
|
|
456
490
|
),
|
|
457
491
|
vec![CompleteWorkflowExecution { result: None }.into()],
|
|
458
492
|
),
|
|
@@ -465,7 +499,7 @@ async fn activity_timeout_no_double_resolve() {
|
|
|
465
499
|
|
|
466
500
|
#[tokio::test]
|
|
467
501
|
async fn only_returns_cancels_for_desired_queue() {
|
|
468
|
-
let mut mock_gateway =
|
|
502
|
+
let mut mock_gateway = mock_gateway();
|
|
469
503
|
let seen_cancel = Arc::new(Notify::new());
|
|
470
504
|
let sc = seen_cancel.clone();
|
|
471
505
|
mock_gateway
|
|
@@ -478,6 +512,10 @@ async fn only_returns_cancels_for_desired_queue() {
|
|
|
478
512
|
cancel_requested: true,
|
|
479
513
|
})
|
|
480
514
|
});
|
|
515
|
+
mock_gateway
|
|
516
|
+
.expect_cancel_activity_task()
|
|
517
|
+
.times(1)
|
|
518
|
+
.returning(|_, _| Ok(RespondActivityTaskCanceledResponse::default()));
|
|
481
519
|
|
|
482
520
|
let mut w1 = MockWorker::for_queue("q1");
|
|
483
521
|
w1.act_poller = Some(mock_poller_from_resps([PollActivityTaskQueueResponse {
|
|
@@ -515,12 +553,130 @@ async fn only_returns_cancels_for_desired_queue() {
|
|
|
515
553
|
}
|
|
516
554
|
};
|
|
517
555
|
assert_matches!(
|
|
518
|
-
q1_res,
|
|
556
|
+
&q1_res,
|
|
519
557
|
ActivityTask {
|
|
520
558
|
variant: Some(activity_task::Variant::Cancel(_)),
|
|
521
559
|
..
|
|
522
560
|
}
|
|
523
561
|
);
|
|
562
|
+
// act needs to complete to finalize shutdown
|
|
563
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
564
|
+
task_token: q1_res.task_token,
|
|
565
|
+
task_queue: "q1".to_string(),
|
|
566
|
+
result: Some(ActivityExecutionResult::cancel_from_details(None)),
|
|
567
|
+
})
|
|
568
|
+
.await
|
|
569
|
+
.unwrap();
|
|
524
570
|
|
|
525
571
|
core.shutdown().await;
|
|
526
572
|
}
|
|
573
|
+
|
|
574
|
+
#[tokio::test]
|
|
575
|
+
async fn can_heartbeat_acts_during_shutdown() {
|
|
576
|
+
let mut mock_gateway = mock_gateway();
|
|
577
|
+
mock_gateway
|
|
578
|
+
.expect_record_activity_heartbeat()
|
|
579
|
+
.times(1)
|
|
580
|
+
.returning(|_, _| {
|
|
581
|
+
Ok(RecordActivityTaskHeartbeatResponse {
|
|
582
|
+
cancel_requested: false,
|
|
583
|
+
})
|
|
584
|
+
});
|
|
585
|
+
mock_gateway
|
|
586
|
+
.expect_complete_activity_task()
|
|
587
|
+
.times(1)
|
|
588
|
+
.returning(|_, _| Ok(RespondActivityTaskCompletedResponse::default()));
|
|
589
|
+
|
|
590
|
+
let core = mock_core(MocksHolder::from_gateway_with_responses(
|
|
591
|
+
mock_gateway,
|
|
592
|
+
[],
|
|
593
|
+
[PollActivityTaskQueueResponse {
|
|
594
|
+
task_token: vec![1],
|
|
595
|
+
activity_id: "act1".to_string(),
|
|
596
|
+
heartbeat_timeout: Some(Duration::from_millis(1).into()),
|
|
597
|
+
..Default::default()
|
|
598
|
+
}],
|
|
599
|
+
));
|
|
600
|
+
|
|
601
|
+
let act = core.poll_activity_task(TEST_Q).await.unwrap();
|
|
602
|
+
let complete_order = RefCell::new(vec![]);
|
|
603
|
+
// Start shutdown before completing the activity
|
|
604
|
+
let shutdown_fut = async {
|
|
605
|
+
core.shutdown().await;
|
|
606
|
+
complete_order.borrow_mut().push(1);
|
|
607
|
+
};
|
|
608
|
+
let complete_fut = async {
|
|
609
|
+
core.record_activity_heartbeat(ActivityHeartbeat {
|
|
610
|
+
task_token: act.task_token.clone(),
|
|
611
|
+
task_queue: TEST_Q.to_string(),
|
|
612
|
+
details: vec![vec![1_u8, 2, 3].into()],
|
|
613
|
+
});
|
|
614
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
615
|
+
task_token: act.task_token,
|
|
616
|
+
task_queue: TEST_Q.to_string(),
|
|
617
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
618
|
+
})
|
|
619
|
+
.await
|
|
620
|
+
.unwrap();
|
|
621
|
+
complete_order.borrow_mut().push(2);
|
|
622
|
+
};
|
|
623
|
+
join!(shutdown_fut, complete_fut);
|
|
624
|
+
assert_eq!(&complete_order.into_inner(), &[2, 1])
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/// Verifies that if a user has tried to record a heartbeat and then immediately after failed the
|
|
628
|
+
/// activity, that we flush those details before reporting the failure completion.
|
|
629
|
+
#[tokio::test]
|
|
630
|
+
async fn complete_act_with_fail_flushes_heartbeat() {
|
|
631
|
+
let last_hb = 50;
|
|
632
|
+
let mut mock_gateway = mock_gateway();
|
|
633
|
+
let last_seen_payload = Rc::new(RefCell::new(None));
|
|
634
|
+
let lsp = last_seen_payload.clone();
|
|
635
|
+
mock_gateway
|
|
636
|
+
.expect_record_activity_heartbeat()
|
|
637
|
+
// Two times b/c we always record the first heartbeat, and we'll flush the last
|
|
638
|
+
.times(2)
|
|
639
|
+
.returning_st(move |_, payload| {
|
|
640
|
+
*lsp.borrow_mut() = payload;
|
|
641
|
+
Ok(RecordActivityTaskHeartbeatResponse {
|
|
642
|
+
cancel_requested: false,
|
|
643
|
+
})
|
|
644
|
+
});
|
|
645
|
+
mock_gateway
|
|
646
|
+
.expect_fail_activity_task()
|
|
647
|
+
.times(1)
|
|
648
|
+
.returning(|_, _| Ok(RespondActivityTaskFailedResponse::default()));
|
|
649
|
+
|
|
650
|
+
let core = mock_core(MocksHolder::from_gateway_with_responses(
|
|
651
|
+
mock_gateway,
|
|
652
|
+
[],
|
|
653
|
+
[PollActivityTaskQueueResponse {
|
|
654
|
+
task_token: vec![1],
|
|
655
|
+
activity_id: "act1".to_string(),
|
|
656
|
+
heartbeat_timeout: Some(Duration::from_secs(10).into()),
|
|
657
|
+
..Default::default()
|
|
658
|
+
}],
|
|
659
|
+
));
|
|
660
|
+
|
|
661
|
+
let act = core.poll_activity_task(TEST_Q).await.unwrap();
|
|
662
|
+
// Record a bunch of heartbeats
|
|
663
|
+
for i in 1..=last_hb {
|
|
664
|
+
core.record_activity_heartbeat(ActivityHeartbeat {
|
|
665
|
+
task_token: act.task_token.clone(),
|
|
666
|
+
task_queue: TEST_Q.to_string(),
|
|
667
|
+
details: vec![vec![i].into()],
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
671
|
+
task_token: act.task_token.clone(),
|
|
672
|
+
task_queue: TEST_Q.to_string(),
|
|
673
|
+
result: Some(ActivityExecutionResult::fail("Ahh".into())),
|
|
674
|
+
})
|
|
675
|
+
.await
|
|
676
|
+
.unwrap();
|
|
677
|
+
core.shutdown().await;
|
|
678
|
+
|
|
679
|
+
// Verify the last seen call to record a heartbeat had the last detail payload
|
|
680
|
+
let last_seen_payload = &last_seen_payload.take().unwrap().payloads[0];
|
|
681
|
+
assert_eq!(last_seen_payload.data, &[last_hb]);
|
|
682
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
|
|
3
|
-
prototype_rust_sdk::{
|
|
4
|
-
ChildWorkflowOptions, TestRustWorker, WfContext, WorkflowFunction, WorkflowResult,
|
|
5
|
-
},
|
|
2
|
+
replay::DEFAULT_WORKFLOW_TYPE,
|
|
6
3
|
test_help::{
|
|
7
|
-
build_mock_pollers, canned_histories, mock_core, MockPollCfg, ResponseType,
|
|
8
|
-
DEFAULT_WORKFLOW_TYPE, TEST_Q,
|
|
4
|
+
build_mock_pollers, canned_histories, mock_core, MockPollCfg, ResponseType, TEST_Q,
|
|
9
5
|
},
|
|
10
6
|
workflow::managed_wf::ManagedWFFunc,
|
|
11
7
|
};
|
|
12
8
|
use std::sync::Arc;
|
|
9
|
+
use temporal_client::mocks::mock_gateway;
|
|
10
|
+
use temporal_sdk::{
|
|
11
|
+
ChildWorkflowOptions, TestRustWorker, WfContext, WorkflowFunction, WorkflowResult,
|
|
12
|
+
};
|
|
13
13
|
use temporal_sdk_core_protos::coresdk::child_workflow::{
|
|
14
14
|
child_workflow_result, ChildWorkflowCancellationType,
|
|
15
15
|
};
|
|
@@ -25,13 +25,13 @@ async fn signal_child_workflow(#[case] serial: bool) {
|
|
|
25
25
|
let wf_id = "fakeid";
|
|
26
26
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
27
27
|
let t = canned_histories::single_child_workflow_signaled("child-id-1", SIGNAME);
|
|
28
|
-
let mock =
|
|
28
|
+
let mock = mock_gateway();
|
|
29
29
|
let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
|
|
30
30
|
let mock = build_mock_pollers(mh);
|
|
31
31
|
let core = mock_core(mock);
|
|
32
32
|
let mut worker = TestRustWorker::new(Arc::new(core), TEST_Q.to_string(), None);
|
|
33
33
|
|
|
34
|
-
let wf = move |
|
|
34
|
+
let wf = move |ctx: WfContext| async move {
|
|
35
35
|
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
36
36
|
workflow_id: "child-id-1".to_string(),
|
|
37
37
|
workflow_type: "child".to_string(),
|
|
@@ -39,16 +39,16 @@ async fn signal_child_workflow(#[case] serial: bool) {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
let start_res = child
|
|
42
|
-
.start(&
|
|
42
|
+
.start(&ctx)
|
|
43
43
|
.await
|
|
44
44
|
.into_started()
|
|
45
45
|
.expect("Child should get started");
|
|
46
46
|
let (sigres, res) = if serial {
|
|
47
|
-
let sigres = start_res.signal(&
|
|
47
|
+
let sigres = start_res.signal(&ctx, SIGNAME, b"Hi!").await;
|
|
48
48
|
let res = start_res.result().await;
|
|
49
49
|
(sigres, res)
|
|
50
50
|
} else {
|
|
51
|
-
let sigfut = start_res.signal(&
|
|
51
|
+
let sigfut = start_res.signal(&ctx, SIGNAME, b"Hi!");
|
|
52
52
|
let resfut = start_res.result();
|
|
53
53
|
join!(sigfut, resfut)
|
|
54
54
|
};
|
|
@@ -65,7 +65,7 @@ async fn signal_child_workflow(#[case] serial: bool) {
|
|
|
65
65
|
worker.run_until_done().await.unwrap();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
async fn parent_cancels_child_wf(
|
|
68
|
+
async fn parent_cancels_child_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
69
69
|
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
70
70
|
workflow_id: "child-id-1".to_string(),
|
|
71
71
|
workflow_type: "child".to_string(),
|
|
@@ -74,11 +74,11 @@ async fn parent_cancels_child_wf(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
let start_res = child
|
|
77
|
-
.start(&
|
|
77
|
+
.start(&ctx)
|
|
78
78
|
.await
|
|
79
79
|
.into_started()
|
|
80
80
|
.expect("Child should get started");
|
|
81
|
-
let cancel_fut = start_res.cancel(&
|
|
81
|
+
let cancel_fut = start_res.cancel(&ctx);
|
|
82
82
|
let resfut = start_res.result();
|
|
83
83
|
let (cancel_res, res) = join!(cancel_fut, resfut);
|
|
84
84
|
cancel_res.expect("cancel result is ok");
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
|
|
3
|
-
prototype_rust_sdk::{TestRustWorker, WfContext, WorkflowResult},
|
|
2
|
+
replay::DEFAULT_WORKFLOW_TYPE,
|
|
4
3
|
test_help::{
|
|
5
|
-
build_mock_pollers, canned_histories, mock_core, MockPollCfg, ResponseType,
|
|
6
|
-
DEFAULT_WORKFLOW_TYPE, TEST_Q,
|
|
4
|
+
build_mock_pollers, canned_histories, mock_core, MockPollCfg, ResponseType, TEST_Q,
|
|
7
5
|
},
|
|
8
6
|
};
|
|
9
7
|
use std::{
|
|
@@ -13,10 +11,12 @@ use std::{
|
|
|
13
11
|
},
|
|
14
12
|
time::Duration,
|
|
15
13
|
};
|
|
14
|
+
use temporal_client::mocks::mock_gateway;
|
|
15
|
+
use temporal_sdk::{TestRustWorker, WfContext, WorkflowResult};
|
|
16
16
|
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowTaskFailedCause;
|
|
17
17
|
|
|
18
18
|
static DID_FAIL: AtomicBool = AtomicBool::new(false);
|
|
19
|
-
pub async fn timer_wf_fails_once(
|
|
19
|
+
pub async fn timer_wf_fails_once(ctx: WfContext) -> WorkflowResult<()> {
|
|
20
20
|
ctx.timer(Duration::from_secs(1)).await;
|
|
21
21
|
if DID_FAIL
|
|
22
22
|
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
|
@@ -34,7 +34,7 @@ async fn test_wf_task_rejected_properly() {
|
|
|
34
34
|
let wf_id = "fakeid";
|
|
35
35
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
36
36
|
let t = canned_histories::workflow_fails_with_failure_after_timer("1");
|
|
37
|
-
let mock =
|
|
37
|
+
let mock = mock_gateway();
|
|
38
38
|
let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2, 2], mock);
|
|
39
39
|
// We should see one wft failure which has unspecified cause, since panics don't have a defined
|
|
40
40
|
// type.
|
|
@@ -63,7 +63,7 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
63
63
|
let wf_id = "fakeid";
|
|
64
64
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
65
65
|
let t = canned_histories::single_timer_wf_completes("1");
|
|
66
|
-
let mock =
|
|
66
|
+
let mock = mock_gateway();
|
|
67
67
|
let mut mh = MockPollCfg::from_resp_batches(
|
|
68
68
|
wf_id,
|
|
69
69
|
t,
|
|
@@ -85,7 +85,7 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
85
85
|
let mut worker = TestRustWorker::new(Arc::new(core), TEST_Q.to_string(), None);
|
|
86
86
|
|
|
87
87
|
let started_count: &'static _ = Box::leak(Box::new(AtomicUsize::new(0)));
|
|
88
|
-
worker.register_wf(wf_type.to_owned(), move |
|
|
88
|
+
worker.register_wf(wf_type.to_owned(), move |ctx: WfContext| async move {
|
|
89
89
|
// The workflow is replaying all of history, so the when it schedules an extra timer it
|
|
90
90
|
// should not have, it causes a nondeterminism error.
|
|
91
91
|
if started_count.fetch_add(1, Ordering::Relaxed) == 0 {
|