@temporalio/core-bridge 1.5.2 → 1.7.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 +304 -112
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +9 -4
- 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 +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +2 -4
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +29 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +20 -10
- package/sdk-core/client/src/lib.rs +215 -39
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +4 -4
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +25 -12
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +204 -14
- package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +165 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
- package/sdk-core/core/src/core_tests/queries.rs +34 -16
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
- package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
- package/sdk-core/core/src/internal_flags.rs +155 -0
- package/sdk-core/core/src/lib.rs +16 -9
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +60 -21
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +73 -14
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
- package/sdk-core/core/src/worker/activities.rs +350 -175
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +183 -64
- package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
- package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
- package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
- package/sdk-core/core-api/Cargo.toml +2 -1
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +19 -9
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +19 -1
- package/sdk-core/etc/deps.svg +115 -140
- package/sdk-core/etc/regen-depgraph.sh +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +6 -6
- package/sdk-core/protos/api_upstream/build/go.mod +7 -0
- package/sdk-core/protos/api_upstream/build/go.sum +5 -0
- package/sdk-core/protos/api_upstream/build/tools.go +29 -0
- package/sdk-core/protos/api_upstream/go.mod +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
- package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- package/sdk-core/sdk/Cargo.toml +5 -4
- package/sdk-core/sdk/src/lib.rs +108 -26
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +16 -15
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- package/sdk-core/sdk-core-protos/build.rs +36 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
- package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
- package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +82 -23
- package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- package/sdk-core/test-utils/src/workflows.rs +29 -0
- package/sdk-core/tests/fuzzy_workflow.rs +130 -0
- package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
- package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
- package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
- package/sdk-core/tests/main.rs +3 -13
- package/sdk-core/tests/runner.rs +75 -36
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/bridge-ffi/Cargo.toml +0 -24
- package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- package/sdk-core/bridge-ffi/build.rs +0 -25
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
- package/sdk-core/bridge-ffi/src/lib.rs +0 -746
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- package/sdk-core/sdk/src/conversions.rs +0 -8
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use std::{sync::Arc, time::Duration};
|
|
3
3
|
use temporal_client::{
|
|
4
|
-
ListClosedFilters, ListOpenFilters, Namespace,
|
|
5
|
-
|
|
4
|
+
ListClosedFilters, ListOpenFilters, Namespace, RegisterNamespaceOptions, StartTimeFilter,
|
|
5
|
+
WorkflowClientTrait, WorkflowExecutionFilter,
|
|
6
6
|
};
|
|
7
7
|
use temporal_sdk_core_protos::coresdk::workflow_activation::{
|
|
8
8
|
workflow_activation_job, WorkflowActivationJob,
|
|
9
9
|
};
|
|
10
10
|
use temporal_sdk_core_test_utils::{
|
|
11
|
-
get_integ_server_options, CoreWfStarter, WorkerTestHelpers,
|
|
11
|
+
drain_pollers_and_shutdown, get_integ_server_options, CoreWfStarter, WorkerTestHelpers,
|
|
12
|
+
NAMESPACE,
|
|
12
13
|
};
|
|
14
|
+
use tokio::time::sleep;
|
|
13
15
|
|
|
14
16
|
#[tokio::test]
|
|
15
17
|
async fn client_list_open_closed_workflow_executions() {
|
|
@@ -22,9 +24,7 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
22
24
|
let latest = earliest + Duration::from_secs(60);
|
|
23
25
|
|
|
24
26
|
// start workflow
|
|
25
|
-
let run_id = starter
|
|
26
|
-
.start_wf_with_id(wf_name.to_owned(), WorkflowOptions::default())
|
|
27
|
-
.await;
|
|
27
|
+
let run_id = starter.start_wf_with_id(wf_name.to_owned()).await;
|
|
28
28
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
29
29
|
assert_matches!(
|
|
30
30
|
task.jobs.as_slice(),
|
|
@@ -52,28 +52,86 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
52
52
|
|
|
53
53
|
// Complete workflow
|
|
54
54
|
core.complete_execution(&task.run_id).await;
|
|
55
|
+
drain_pollers_and_shutdown(&core).await;
|
|
55
56
|
|
|
56
|
-
// List above CLOSED workflow
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
57
|
+
// List above CLOSED workflow. Visibility doesn't always update immediately so we give this a
|
|
58
|
+
// few tries.
|
|
59
|
+
let mut passed = false;
|
|
60
|
+
for _ in 1..=5 {
|
|
61
|
+
let closed_workflows = client
|
|
62
|
+
.list_closed_workflow_executions(
|
|
63
|
+
1,
|
|
64
|
+
Default::default(),
|
|
65
|
+
Some(StartTimeFilter {
|
|
66
|
+
earliest_time: Some(earliest).and_then(|t| t.try_into().ok()),
|
|
67
|
+
latest_time: Some(latest).and_then(|t| t.try_into().ok()),
|
|
68
|
+
}),
|
|
69
|
+
Some(ListClosedFilters::ExecutionFilter(
|
|
70
|
+
WorkflowExecutionFilter {
|
|
71
|
+
workflow_id: wf_name.clone(),
|
|
72
|
+
run_id: run_id.clone(),
|
|
73
|
+
},
|
|
74
|
+
)),
|
|
75
|
+
)
|
|
76
|
+
.await
|
|
77
|
+
.unwrap();
|
|
78
|
+
if closed_workflows.executions.len() == 1 {
|
|
79
|
+
let workflow = &closed_workflows.executions[0];
|
|
80
|
+
if workflow.execution.as_ref().unwrap().workflow_id == wf_name {
|
|
81
|
+
passed = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
sleep(Duration::from_millis(100)).await;
|
|
86
|
+
}
|
|
87
|
+
assert!(passed);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[tokio::test]
|
|
91
|
+
async fn client_create_namespace() {
|
|
92
|
+
let client = Arc::new(
|
|
93
|
+
get_integ_server_options()
|
|
94
|
+
.connect(NAMESPACE.to_owned(), None, None)
|
|
95
|
+
.await
|
|
96
|
+
.expect("Must connect"),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
let register_options = RegisterNamespaceOptions::builder()
|
|
100
|
+
.namespace("test-create-namespace")
|
|
101
|
+
.description("it's alive")
|
|
102
|
+
.build()
|
|
103
|
+
.unwrap();
|
|
104
|
+
|
|
105
|
+
client
|
|
106
|
+
.register_namespace(register_options.clone())
|
|
72
107
|
.await
|
|
73
108
|
.unwrap();
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
109
|
+
|
|
110
|
+
//#Hack, not sure how else to wait for a proper response. RegisterNamespace isn't safe to read
|
|
111
|
+
//after write
|
|
112
|
+
let mut attempts = 0;
|
|
113
|
+
let wait_time = Duration::from_secs(1);
|
|
114
|
+
loop {
|
|
115
|
+
attempts += 1;
|
|
116
|
+
let resp = client
|
|
117
|
+
.describe_namespace(Namespace::Name(register_options.namespace.clone()))
|
|
118
|
+
.await;
|
|
119
|
+
|
|
120
|
+
match resp {
|
|
121
|
+
Ok(n) => {
|
|
122
|
+
let namespace_info = n.namespace_info.unwrap();
|
|
123
|
+
assert_eq!(namespace_info.name, register_options.namespace);
|
|
124
|
+
assert_eq!(namespace_info.description, register_options.description);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
_ => {
|
|
128
|
+
if attempts == 12 {
|
|
129
|
+
panic!("failed to query registered namespace");
|
|
130
|
+
}
|
|
131
|
+
sleep(wait_time).await
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
77
135
|
}
|
|
78
136
|
|
|
79
137
|
#[tokio::test]
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
use anyhow::anyhow;
|
|
1
2
|
use assert_matches::assert_matches;
|
|
3
|
+
use futures_util::future::join_all;
|
|
2
4
|
use std::time::Duration;
|
|
3
5
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
|
|
4
6
|
use temporal_sdk::{
|
|
5
|
-
ActContext, ActExitValue, ActivityOptions, CancellableFuture,
|
|
7
|
+
ActContext, ActExitValue, ActivityCancelledError, ActivityOptions, CancellableFuture,
|
|
8
|
+
WfContext, WorkflowResult,
|
|
6
9
|
};
|
|
7
10
|
use temporal_sdk_core_protos::{
|
|
8
11
|
coresdk::{
|
|
@@ -19,16 +22,17 @@ use temporal_sdk_core_protos::{
|
|
|
19
22
|
IntoCompletion,
|
|
20
23
|
},
|
|
21
24
|
temporal::api::{
|
|
22
|
-
common::v1::{ActivityType, Payload, Payloads},
|
|
25
|
+
common::v1::{ActivityType, Payload, Payloads, RetryPolicy},
|
|
23
26
|
enums::v1::RetryState,
|
|
24
27
|
failure::v1::{failure::FailureInfo, ActivityFailureInfo, Failure},
|
|
25
28
|
},
|
|
26
|
-
TaskToken,
|
|
29
|
+
TaskToken, DEFAULT_ACTIVITY_TYPE,
|
|
27
30
|
};
|
|
28
31
|
use temporal_sdk_core_test_utils::{
|
|
29
|
-
init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter,
|
|
32
|
+
drain_pollers_and_shutdown, init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter,
|
|
33
|
+
WorkerTestHelpers,
|
|
30
34
|
};
|
|
31
|
-
use tokio::time::sleep;
|
|
35
|
+
use tokio::{join, sync::Semaphore, time::sleep};
|
|
32
36
|
|
|
33
37
|
pub async fn one_activity_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
34
38
|
ctx.activity(ActivityOptions {
|
|
@@ -97,7 +101,7 @@ async fn activity_workflow() {
|
|
|
97
101
|
assert_matches!(
|
|
98
102
|
task.variant,
|
|
99
103
|
Some(act_task::Variant::Start(start_activity)) => {
|
|
100
|
-
assert_eq!(start_activity.activity_type,
|
|
104
|
+
assert_eq!(start_activity.activity_type, DEFAULT_ACTIVITY_TYPE.to_string())
|
|
101
105
|
}
|
|
102
106
|
);
|
|
103
107
|
let response_payload = Payload {
|
|
@@ -154,16 +158,78 @@ async fn activity_non_retryable_failure() {
|
|
|
154
158
|
)
|
|
155
159
|
.await
|
|
156
160
|
.unwrap();
|
|
157
|
-
// Poll activity and verify that it's been scheduled
|
|
161
|
+
// Poll activity and verify that it's been scheduled
|
|
158
162
|
let task = core.poll_activity_task().await.unwrap();
|
|
163
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
164
|
+
// Fail activity with non-retryable error
|
|
165
|
+
let failure = Failure::application_failure("activity failed".to_string(), true);
|
|
166
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
167
|
+
task_token: task.task_token,
|
|
168
|
+
result: Some(ActivityExecutionResult::fail(failure.clone())),
|
|
169
|
+
})
|
|
170
|
+
.await
|
|
171
|
+
.unwrap();
|
|
172
|
+
// Poll workflow task and verify that activity has failed.
|
|
173
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
159
174
|
assert_matches!(
|
|
160
|
-
task.
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
task.jobs.as_slice(),
|
|
176
|
+
[
|
|
177
|
+
WorkflowActivationJob {
|
|
178
|
+
variant: Some(workflow_activation_job::Variant::ResolveActivity(
|
|
179
|
+
ResolveActivity {seq, result: Some(ActivityResolution{
|
|
180
|
+
status: Some(act_res::Status::Failed(activity_result::Failure{
|
|
181
|
+
failure: Some(f),
|
|
182
|
+
}))})}
|
|
183
|
+
)),
|
|
184
|
+
},
|
|
185
|
+
] => {
|
|
186
|
+
assert_eq!(*seq, 0);
|
|
187
|
+
assert_eq!(f, &Failure{
|
|
188
|
+
message: "Activity task failed".to_owned(),
|
|
189
|
+
cause: Some(Box::new(failure)),
|
|
190
|
+
failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
|
|
191
|
+
activity_id: "act-1".to_owned(),
|
|
192
|
+
activity_type: Some(ActivityType {
|
|
193
|
+
name: DEFAULT_ACTIVITY_TYPE.to_owned(),
|
|
194
|
+
}),
|
|
195
|
+
scheduled_event_id: 5,
|
|
196
|
+
started_event_id: 6,
|
|
197
|
+
identity: "integ_tester".to_owned(),
|
|
198
|
+
retry_state: RetryState::NonRetryableFailure as i32,
|
|
199
|
+
})),
|
|
200
|
+
..Default::default()
|
|
201
|
+
});
|
|
163
202
|
}
|
|
164
203
|
);
|
|
204
|
+
core.complete_execution(&task.run_id).await;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#[tokio::test]
|
|
208
|
+
async fn activity_non_retryable_failure_with_error() {
|
|
209
|
+
let mut starter = init_core_and_create_wf("activity_non_retryable_failure").await;
|
|
210
|
+
let core = starter.get_worker().await;
|
|
211
|
+
let task_q = starter.get_task_queue();
|
|
212
|
+
let activity_id = "act-1";
|
|
213
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
214
|
+
// Complete workflow task and schedule activity
|
|
215
|
+
core.complete_workflow_activation(
|
|
216
|
+
schedule_activity_cmd(
|
|
217
|
+
0,
|
|
218
|
+
task_q,
|
|
219
|
+
activity_id,
|
|
220
|
+
ActivityCancellationType::TryCancel,
|
|
221
|
+
Duration::from_secs(60),
|
|
222
|
+
Duration::from_secs(60),
|
|
223
|
+
)
|
|
224
|
+
.into_completion(task.run_id),
|
|
225
|
+
)
|
|
226
|
+
.await
|
|
227
|
+
.unwrap();
|
|
228
|
+
// Poll activity and verify that it's been scheduled
|
|
229
|
+
let task = core.poll_activity_task().await.unwrap();
|
|
230
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
165
231
|
// Fail activity with non-retryable error
|
|
166
|
-
let failure = Failure::
|
|
232
|
+
let failure = Failure::application_failure_from_error(anyhow!("activity failed"), true);
|
|
167
233
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
168
234
|
task_token: task.task_token,
|
|
169
235
|
result: Some(ActivityExecutionResult::fail(failure.clone())),
|
|
@@ -191,7 +257,7 @@ async fn activity_non_retryable_failure() {
|
|
|
191
257
|
failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
|
|
192
258
|
activity_id: "act-1".to_owned(),
|
|
193
259
|
activity_type: Some(ActivityType {
|
|
194
|
-
name:
|
|
260
|
+
name: DEFAULT_ACTIVITY_TYPE.to_owned(),
|
|
195
261
|
}),
|
|
196
262
|
scheduled_event_id: 5,
|
|
197
263
|
started_event_id: 6,
|
|
@@ -228,12 +294,7 @@ async fn activity_retry() {
|
|
|
228
294
|
.unwrap();
|
|
229
295
|
// Poll activity 1st time
|
|
230
296
|
let task = core.poll_activity_task().await.unwrap();
|
|
231
|
-
assert_matches!(
|
|
232
|
-
task.variant,
|
|
233
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
234
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
235
|
-
}
|
|
236
|
-
);
|
|
297
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
237
298
|
// Fail activity with retryable error
|
|
238
299
|
let failure = Failure::application_failure("activity failed".to_string(), false);
|
|
239
300
|
core.complete_activity_task(ActivityTaskCompletion {
|
|
@@ -244,12 +305,7 @@ async fn activity_retry() {
|
|
|
244
305
|
.unwrap();
|
|
245
306
|
// Poll 2nd time
|
|
246
307
|
let task = core.poll_activity_task().await.unwrap();
|
|
247
|
-
assert_matches!(
|
|
248
|
-
task.variant,
|
|
249
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
250
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
251
|
-
}
|
|
252
|
-
);
|
|
308
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
253
309
|
// Complete activity successfully
|
|
254
310
|
let response_payload = Payload {
|
|
255
311
|
data: b"hello ".to_vec(),
|
|
@@ -308,15 +364,10 @@ async fn activity_cancellation_try_cancel() {
|
|
|
308
364
|
)
|
|
309
365
|
.await
|
|
310
366
|
.unwrap();
|
|
311
|
-
// Poll activity and verify that it's been scheduled
|
|
312
|
-
//
|
|
367
|
+
// Poll activity and verify that it's been scheduled, we don't expect to complete it in this
|
|
368
|
+
// test as activity is try-cancelled.
|
|
313
369
|
let activity_task = core.poll_activity_task().await.unwrap();
|
|
314
|
-
assert_matches!(
|
|
315
|
-
activity_task.variant,
|
|
316
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
317
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
318
|
-
}
|
|
319
|
-
);
|
|
370
|
+
assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
|
|
320
371
|
// Poll workflow task and verify that activity has failed.
|
|
321
372
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
322
373
|
assert_matches!(
|
|
@@ -453,15 +504,10 @@ async fn started_activity_timeout() {
|
|
|
453
504
|
)
|
|
454
505
|
.await
|
|
455
506
|
.unwrap();
|
|
456
|
-
// Poll activity and verify that it's been scheduled
|
|
457
|
-
//
|
|
507
|
+
// Poll activity and verify that it's been scheduled, we don't expect to complete it in this
|
|
508
|
+
// test as activity is timed out after 1 second.
|
|
458
509
|
let activity_task = core.poll_activity_task().await.unwrap();
|
|
459
|
-
assert_matches!(
|
|
460
|
-
activity_task.variant,
|
|
461
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
462
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
463
|
-
}
|
|
464
|
-
);
|
|
510
|
+
assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
|
|
465
511
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
466
512
|
assert_matches!(
|
|
467
513
|
task.jobs.as_slice(),
|
|
@@ -517,15 +563,10 @@ async fn activity_cancellation_wait_cancellation_completed() {
|
|
|
517
563
|
)
|
|
518
564
|
.await
|
|
519
565
|
.unwrap();
|
|
520
|
-
// Poll activity and verify that it's been scheduled
|
|
521
|
-
//
|
|
566
|
+
// Poll activity and verify that it's been scheduled, we don't expect to complete it in this
|
|
567
|
+
// test as activity is wait-cancelled.
|
|
522
568
|
let activity_task = core.poll_activity_task().await.unwrap();
|
|
523
|
-
assert_matches!(
|
|
524
|
-
activity_task.variant,
|
|
525
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
526
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
527
|
-
}
|
|
528
|
-
);
|
|
569
|
+
assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
|
|
529
570
|
// Poll workflow task and verify that activity has failed.
|
|
530
571
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
531
572
|
assert_matches!(
|
|
@@ -584,15 +625,10 @@ async fn activity_cancellation_abandon() {
|
|
|
584
625
|
)
|
|
585
626
|
.await
|
|
586
627
|
.unwrap();
|
|
587
|
-
// Poll activity and verify that it's been scheduled
|
|
588
|
-
//
|
|
628
|
+
// Poll activity and verify that it's been scheduled, we don't expect to complete it in this
|
|
629
|
+
// test as activity is abandoned.
|
|
589
630
|
let activity_task = core.poll_activity_task().await.unwrap();
|
|
590
|
-
assert_matches!(
|
|
591
|
-
activity_task.variant,
|
|
592
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
593
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
594
|
-
}
|
|
595
|
-
);
|
|
631
|
+
assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
|
|
596
632
|
// Poll workflow task and verify that activity has failed.
|
|
597
633
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
598
634
|
assert_matches!(
|
|
@@ -640,14 +676,9 @@ async fn async_activity_completion_workflow() {
|
|
|
640
676
|
)
|
|
641
677
|
.await
|
|
642
678
|
.unwrap();
|
|
643
|
-
// Poll activity and verify that it's been scheduled
|
|
679
|
+
// Poll activity and verify that it's been scheduled
|
|
644
680
|
let task = core.poll_activity_task().await.unwrap();
|
|
645
|
-
assert_matches!(
|
|
646
|
-
task.variant,
|
|
647
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
648
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
649
|
-
}
|
|
650
|
-
);
|
|
681
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
651
682
|
let response_payload = Payload {
|
|
652
683
|
data: b"hello ".to_vec(),
|
|
653
684
|
metadata: Default::default(),
|
|
@@ -712,14 +743,9 @@ async fn activity_cancelled_after_heartbeat_times_out() {
|
|
|
712
743
|
)
|
|
713
744
|
.await
|
|
714
745
|
.unwrap();
|
|
715
|
-
// Poll activity and verify that it's been scheduled
|
|
746
|
+
// Poll activity and verify that it's been scheduled
|
|
716
747
|
let task = core.poll_activity_task().await.unwrap();
|
|
717
|
-
assert_matches!(
|
|
718
|
-
task.variant,
|
|
719
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
720
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
721
|
-
}
|
|
722
|
-
);
|
|
748
|
+
assert_matches!(task.variant, Some(act_task::Variant::Start(_)));
|
|
723
749
|
// Delay the heartbeat
|
|
724
750
|
sleep(Duration::from_secs(2)).await;
|
|
725
751
|
core.record_activity_heartbeat(ActivityHeartbeat {
|
|
@@ -741,7 +767,7 @@ async fn activity_cancelled_after_heartbeat_times_out() {
|
|
|
741
767
|
.unwrap();
|
|
742
768
|
|
|
743
769
|
// Verify shutdown completes
|
|
744
|
-
core
|
|
770
|
+
drain_pollers_and_shutdown(&core).await;
|
|
745
771
|
// Cleanup just in case
|
|
746
772
|
starter
|
|
747
773
|
.get_client()
|
|
@@ -822,7 +848,7 @@ async fn it_can_complete_async() {
|
|
|
822
848
|
Some(act_res::Status::Completed(activity_result::Success { result })) => result
|
|
823
849
|
.map(|p| String::from_json_payload(&p).unwrap())
|
|
824
850
|
.unwrap(),
|
|
825
|
-
_ => panic!("activity task failed {:?}"
|
|
851
|
+
_ => panic!("activity task failed {activity_resolution:?}"),
|
|
826
852
|
};
|
|
827
853
|
|
|
828
854
|
assert_eq!(&res, async_response);
|
|
@@ -876,3 +902,66 @@ async fn it_can_complete_async() {
|
|
|
876
902
|
|
|
877
903
|
worker.run_until_done().await.unwrap();
|
|
878
904
|
}
|
|
905
|
+
|
|
906
|
+
#[tokio::test]
|
|
907
|
+
async fn graceful_shutdown() {
|
|
908
|
+
let wf_name = "graceful_shutdown";
|
|
909
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
910
|
+
starter.worker_config.graceful_shutdown_period = Some(Duration::from_millis(500));
|
|
911
|
+
let mut worker = starter.worker().await;
|
|
912
|
+
let client = starter.get_client().await;
|
|
913
|
+
worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
|
|
914
|
+
let act_futs = (1..=10).map(|_| {
|
|
915
|
+
ctx.activity(ActivityOptions {
|
|
916
|
+
activity_type: "sleeper".to_string(),
|
|
917
|
+
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
918
|
+
retry_policy: Some(RetryPolicy {
|
|
919
|
+
maximum_attempts: 1,
|
|
920
|
+
..Default::default()
|
|
921
|
+
}),
|
|
922
|
+
cancellation_type: ActivityCancellationType::WaitCancellationCompleted,
|
|
923
|
+
input: "hi".as_json_payload().unwrap(),
|
|
924
|
+
..Default::default()
|
|
925
|
+
})
|
|
926
|
+
});
|
|
927
|
+
join_all(act_futs).await;
|
|
928
|
+
Ok(().into())
|
|
929
|
+
});
|
|
930
|
+
static ACTS_STARTED: Semaphore = Semaphore::const_new(0);
|
|
931
|
+
static ACTS_DONE: Semaphore = Semaphore::const_new(0);
|
|
932
|
+
worker.register_activity("sleeper", |ctx: ActContext, _: String| async move {
|
|
933
|
+
ACTS_STARTED.add_permits(1);
|
|
934
|
+
// just wait to be cancelled
|
|
935
|
+
ctx.cancelled().await;
|
|
936
|
+
ACTS_DONE.add_permits(1);
|
|
937
|
+
Result::<(), _>::Err(ActivityCancelledError::default().into())
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
worker
|
|
941
|
+
.submit_wf(
|
|
942
|
+
wf_name.to_owned(),
|
|
943
|
+
wf_name.to_owned(),
|
|
944
|
+
vec![],
|
|
945
|
+
WorkflowOptions::default(),
|
|
946
|
+
)
|
|
947
|
+
.await
|
|
948
|
+
.unwrap();
|
|
949
|
+
|
|
950
|
+
let handle = worker.inner_mut().shutdown_handle();
|
|
951
|
+
let shutdowner = async {
|
|
952
|
+
// Wait for all acts to be started before initiating shutdown
|
|
953
|
+
let _ = ACTS_STARTED.acquire_many(10).await;
|
|
954
|
+
handle();
|
|
955
|
+
// Kill workflow once all acts are cancelled. This also ensures we actually see all the
|
|
956
|
+
// cancels, otherwise run_until_done will hang since the workflow won't complete.
|
|
957
|
+
let _ = ACTS_DONE.acquire_many(10).await;
|
|
958
|
+
client
|
|
959
|
+
.terminate_workflow_execution(wf_name.to_owned(), None)
|
|
960
|
+
.await
|
|
961
|
+
.unwrap();
|
|
962
|
+
};
|
|
963
|
+
let runner = async {
|
|
964
|
+
worker.run_until_done().await.unwrap();
|
|
965
|
+
};
|
|
966
|
+
join!(shutdowner, runner);
|
|
967
|
+
}
|
|
@@ -33,6 +33,7 @@ async fn cancel_receiver(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
|
33
33
|
#[tokio::test]
|
|
34
34
|
async fn sends_cancel_to_other_wf() {
|
|
35
35
|
let mut starter = CoreWfStarter::new("sends_cancel_to_other_wf");
|
|
36
|
+
starter.no_remote_activities();
|
|
36
37
|
let mut worker = starter.worker().await;
|
|
37
38
|
worker.register_wf("sender", cancel_sender);
|
|
38
39
|
worker.register_wf("receiver", cancel_receiver);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use std::time::Duration;
|
|
2
|
-
use temporal_client::
|
|
2
|
+
use temporal_client::WorkflowClientTrait;
|
|
3
3
|
use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
|
|
4
4
|
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowExecutionStatus;
|
|
5
5
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
@@ -21,25 +21,18 @@ async fn cancelled_wf(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
|
21
21
|
async fn cancel_during_timer() {
|
|
22
22
|
let wf_name = "cancel_during_timer";
|
|
23
23
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
24
|
+
starter.no_remote_activities();
|
|
24
25
|
let mut worker = starter.worker().await;
|
|
25
26
|
let client = starter.get_client().await;
|
|
26
27
|
worker.register_wf(wf_name.to_string(), cancelled_wf);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.submit_wf(
|
|
30
|
-
wf_name.to_owned(),
|
|
31
|
-
wf_name.to_owned(),
|
|
32
|
-
vec![],
|
|
33
|
-
WorkflowOptions::default(),
|
|
34
|
-
)
|
|
35
|
-
.await
|
|
36
|
-
.unwrap();
|
|
28
|
+
starter.start_with_worker(wf_name, &mut worker).await;
|
|
29
|
+
let wf_id = starter.get_task_queue().to_string();
|
|
37
30
|
|
|
38
31
|
let canceller = async {
|
|
39
32
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
40
33
|
// Cancel the workflow externally
|
|
41
34
|
client
|
|
42
|
-
.cancel_workflow_execution(
|
|
35
|
+
.cancel_workflow_execution(wf_id.clone(), None, "Dieee".to_string(), None)
|
|
43
36
|
.await
|
|
44
37
|
.unwrap();
|
|
45
38
|
};
|
|
@@ -47,7 +40,7 @@ async fn cancel_during_timer() {
|
|
|
47
40
|
let (_, res) = tokio::join!(canceller, worker.run_until_done());
|
|
48
41
|
res.unwrap();
|
|
49
42
|
let desc = client
|
|
50
|
-
.describe_workflow_execution(
|
|
43
|
+
.describe_workflow_execution(wf_id, None)
|
|
51
44
|
.await
|
|
52
45
|
.unwrap();
|
|
53
46
|
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
use anyhow::anyhow;
|
|
2
|
-
use
|
|
3
|
-
use
|
|
4
|
-
use
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
use temporal_client::{WorkflowClientTrait, WorkflowOptions};
|
|
4
|
+
use temporal_sdk::{ChildWorkflowOptions, WfContext, WfExitValue, WorkflowResult};
|
|
5
|
+
use temporal_sdk_core_protos::{
|
|
6
|
+
coresdk::child_workflow::{child_workflow_result, ChildWorkflowCancellationType, Success},
|
|
7
|
+
temporal::api::enums::v1::ParentClosePolicy,
|
|
8
|
+
};
|
|
5
9
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
10
|
+
use tokio::sync::Barrier;
|
|
6
11
|
|
|
7
12
|
static PARENT_WF_TYPE: &str = "parent_wf";
|
|
8
13
|
static CHILD_WF_TYPE: &str = "child_wf";
|
|
@@ -32,6 +37,7 @@ async fn parent_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
32
37
|
#[tokio::test]
|
|
33
38
|
async fn child_workflow_happy_path() {
|
|
34
39
|
let mut starter = CoreWfStarter::new("child-workflows");
|
|
40
|
+
starter.no_remote_activities();
|
|
35
41
|
let mut worker = starter.worker().await;
|
|
36
42
|
|
|
37
43
|
worker.register_wf(PARENT_WF_TYPE.to_string(), parent_wf);
|
|
@@ -48,3 +54,74 @@ async fn child_workflow_happy_path() {
|
|
|
48
54
|
.unwrap();
|
|
49
55
|
worker.run_until_done().await.unwrap();
|
|
50
56
|
}
|
|
57
|
+
|
|
58
|
+
#[tokio::test]
|
|
59
|
+
async fn abandoned_child_bug_repro() {
|
|
60
|
+
let mut starter = CoreWfStarter::new("child-workflow-abandon-bug");
|
|
61
|
+
starter.no_remote_activities();
|
|
62
|
+
let mut worker = starter.worker().await;
|
|
63
|
+
let barr: &'static Barrier = Box::leak(Box::new(Barrier::new(2)));
|
|
64
|
+
|
|
65
|
+
worker.register_wf(
|
|
66
|
+
PARENT_WF_TYPE.to_string(),
|
|
67
|
+
move |mut ctx: WfContext| async move {
|
|
68
|
+
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
69
|
+
workflow_id: "abandoned-child".to_owned(),
|
|
70
|
+
workflow_type: CHILD_WF_TYPE.to_owned(),
|
|
71
|
+
parent_close_policy: ParentClosePolicy::Abandon,
|
|
72
|
+
cancel_type: ChildWorkflowCancellationType::Abandon,
|
|
73
|
+
..Default::default()
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
let started = child
|
|
77
|
+
.start(&ctx)
|
|
78
|
+
.await
|
|
79
|
+
.into_started()
|
|
80
|
+
.expect("Child chould start OK");
|
|
81
|
+
barr.wait().await;
|
|
82
|
+
// Wait for cancel signal
|
|
83
|
+
ctx.cancelled().await;
|
|
84
|
+
// Cancel the child immediately
|
|
85
|
+
started.cancel(&ctx);
|
|
86
|
+
// Need to do something else, so we'll see the ChildWorkflowExecutionCanceled event
|
|
87
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
88
|
+
started.result().await;
|
|
89
|
+
Ok(().into())
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
worker.register_wf(CHILD_WF_TYPE.to_string(), |mut ctx: WfContext| async move {
|
|
93
|
+
ctx.cancelled().await;
|
|
94
|
+
Ok(WfExitValue::Cancelled)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
worker
|
|
98
|
+
.submit_wf(
|
|
99
|
+
"parent-abandoner".to_string(),
|
|
100
|
+
PARENT_WF_TYPE.to_owned(),
|
|
101
|
+
vec![],
|
|
102
|
+
WorkflowOptions::default(),
|
|
103
|
+
)
|
|
104
|
+
.await
|
|
105
|
+
.unwrap();
|
|
106
|
+
let client = starter.get_client().await;
|
|
107
|
+
let canceller = async {
|
|
108
|
+
barr.wait().await;
|
|
109
|
+
client
|
|
110
|
+
.cancel_workflow_execution(
|
|
111
|
+
"parent-abandoner".to_string(),
|
|
112
|
+
None,
|
|
113
|
+
"die".to_string(),
|
|
114
|
+
None,
|
|
115
|
+
)
|
|
116
|
+
.await
|
|
117
|
+
.unwrap();
|
|
118
|
+
client
|
|
119
|
+
.cancel_workflow_execution("abandoned-child".to_string(), None, "die".to_string(), None)
|
|
120
|
+
.await
|
|
121
|
+
.unwrap();
|
|
122
|
+
};
|
|
123
|
+
let runner = async move {
|
|
124
|
+
worker.run_until_done().await.unwrap();
|
|
125
|
+
};
|
|
126
|
+
tokio::join!(canceller, runner);
|
|
127
|
+
}
|
|
@@ -21,6 +21,7 @@ async fn continue_as_new_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
21
21
|
async fn continue_as_new_happy_path() {
|
|
22
22
|
let wf_name = "continue_as_new_happy_path";
|
|
23
23
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
24
|
+
starter.no_remote_activities();
|
|
24
25
|
let mut worker = starter.worker().await;
|
|
25
26
|
worker.register_wf(wf_name.to_string(), continue_as_new_wf);
|
|
26
27
|
|
|
@@ -40,11 +41,14 @@ async fn continue_as_new_happy_path() {
|
|
|
40
41
|
async fn continue_as_new_multiple_concurrent() {
|
|
41
42
|
let wf_name = "continue_as_new_multiple_concurrent";
|
|
42
43
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
43
|
-
starter
|
|
44
|
+
starter
|
|
45
|
+
.no_remote_activities()
|
|
46
|
+
.max_cached_workflows(3)
|
|
47
|
+
.max_wft(3);
|
|
44
48
|
let mut worker = starter.worker().await;
|
|
45
49
|
worker.register_wf(wf_name.to_string(), continue_as_new_wf);
|
|
46
50
|
|
|
47
|
-
let wf_names = (1..=20).map(|i| format!("{}-{}"
|
|
51
|
+
let wf_names = (1..=20).map(|i| format!("{wf_name}-{i}"));
|
|
48
52
|
for name in wf_names.clone() {
|
|
49
53
|
worker
|
|
50
54
|
.submit_wf(
|