@temporalio/core-bridge 1.15.0 → 1.16.1
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 +172 -70
- package/lib/native.d.ts +1 -1
- package/package.json +2 -2
- 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/.github/workflows/per-pr.yml +6 -6
- package/sdk-core/AGENTS.md +41 -30
- package/sdk-core/Cargo.toml +3 -0
- package/sdk-core/README.md +15 -9
- package/sdk-core/crates/client/Cargo.toml +4 -0
- package/sdk-core/crates/client/README.md +139 -0
- package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
- package/sdk-core/crates/client/src/callback_based.rs +7 -0
- package/sdk-core/crates/client/src/errors.rs +294 -0
- package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +280 -159
- package/sdk-core/crates/client/src/lib.rs +920 -1326
- package/sdk-core/crates/client/src/metrics.rs +24 -33
- package/sdk-core/crates/client/src/options_structs.rs +457 -0
- package/sdk-core/crates/client/src/replaceable.rs +5 -4
- package/sdk-core/crates/client/src/request_extensions.rs +8 -9
- package/sdk-core/crates/client/src/retry.rs +99 -54
- package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +1 -1
- package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
- package/sdk-core/crates/common/Cargo.toml +61 -2
- package/sdk-core/crates/common/build.rs +742 -12
- package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
- package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
- package/sdk-core/crates/common/protos/api_upstream/buf.yaml +0 -3
- package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
- package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +1166 -770
- package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +1243 -750
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +2 -2
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -3
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +4 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +16 -1
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -6
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +88 -33
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +4 -2
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +5 -5
- package/sdk-core/crates/common/src/activity_definition.rs +20 -0
- package/sdk-core/crates/common/src/data_converters.rs +770 -0
- package/sdk-core/crates/common/src/envconfig.rs +5 -0
- package/sdk-core/crates/common/src/lib.rs +15 -211
- package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
- package/sdk-core/crates/common/src/priority.rs +110 -0
- package/sdk-core/crates/common/src/protos/canned_histories.rs +3 -0
- package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
- package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
- package/sdk-core/crates/common/src/protos/mod.rs +122 -27
- package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
- package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +5 -7
- package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
- package/sdk-core/crates/common/src/telemetry/metrics.rs +268 -223
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
- package/sdk-core/crates/common/src/telemetry.rs +264 -4
- package/sdk-core/crates/common/src/worker.rs +68 -603
- package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
- package/sdk-core/crates/macros/Cargo.toml +5 -1
- package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
- package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
- package/sdk-core/crates/macros/src/lib.rs +138 -512
- package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
- package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
- package/sdk-core/crates/sdk/Cargo.toml +19 -6
- package/sdk-core/crates/sdk/README.md +415 -0
- package/sdk-core/crates/sdk/src/activities.rs +417 -0
- package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
- package/sdk-core/crates/sdk/src/lib.rs +757 -442
- package/sdk-core/crates/sdk/src/workflow_context/options.rs +45 -35
- package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
- package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
- package/sdk-core/crates/sdk/src/workflows.rs +711 -0
- package/sdk-core/crates/sdk-core/Cargo.toml +57 -64
- package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +41 -35
- package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
- package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
- package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
- package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +13 -15
- package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
- package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
- package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
- package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +493 -26
- package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +4 -8
- package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +7 -7
- package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
- package/sdk-core/crates/sdk-core/src/lib.rs +41 -111
- package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
- package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +118 -19
- package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
- package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
- package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +179 -196
- package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -280
- package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +6 -9
- package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
- package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
- package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
- package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +9 -5
- package/sdk-core/crates/sdk-core/src/worker/client.rs +103 -81
- package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +7 -11
- package/sdk-core/crates/sdk-core/src/worker/mod.rs +1124 -229
- package/sdk-core/crates/sdk-core/src/worker/nexus.rs +145 -23
- package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
- package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
- package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +13 -13
- package/sdk-core/crates/sdk-core/src/worker/tuner.rs +28 -8
- package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
- package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
- package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +19 -4
- package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +14 -18
- package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +4 -6
- package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
- package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
- package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
- package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
- package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
- package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
- package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
- package/sdk-core/crates/sdk-core/tests/common/mod.rs +241 -196
- package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
- package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +3 -5
- package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -64
- package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +298 -252
- package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
- package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +16 -12
- package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +48 -40
- package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +327 -255
- package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
- package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +147 -126
- package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
- package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -453
- package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +360 -231
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +248 -185
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -43
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +428 -315
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -56
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -28
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -243
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +101 -42
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -147
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -28
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1036
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -41
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +397 -238
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +414 -189
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +154 -137
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -105
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -38
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -40
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -54
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +363 -226
- package/sdk-core/crates/sdk-core/tests/main.rs +17 -15
- package/sdk-core/crates/sdk-core/tests/manual_tests.rs +207 -152
- package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +65 -34
- package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
- package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +7 -1
- package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +14 -14
- package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +83 -74
- package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +9 -14
- package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +1 -2
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +13 -13
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +6 -6
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +3 -4
- package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +62 -75
- package/sdk-core/rustfmt.toml +2 -1
- package/src/client.rs +205 -318
- package/src/metrics.rs +22 -30
- package/src/runtime.rs +4 -5
- package/src/worker.rs +16 -19
- package/ts/native.ts +1 -1
- package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
- package/sdk-core/crates/common/src/errors.rs +0 -85
- package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
- package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
- package/sdk-core/crates/sdk/src/app_data.rs +0 -37
- package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
|
@@ -2,7 +2,7 @@ use crate::{
|
|
|
2
2
|
common::{CoreWfStarter, WorkflowHandleExt, rand_6_chars},
|
|
3
3
|
integ_tests::mk_nexus_endpoint,
|
|
4
4
|
};
|
|
5
|
-
use anyhow::
|
|
5
|
+
use anyhow::anyhow;
|
|
6
6
|
use assert_matches::assert_matches;
|
|
7
7
|
use std::{
|
|
8
8
|
sync::{
|
|
@@ -11,9 +11,15 @@ use std::{
|
|
|
11
11
|
},
|
|
12
12
|
time::Duration,
|
|
13
13
|
};
|
|
14
|
-
use temporalio_client::{
|
|
14
|
+
use temporalio_client::{
|
|
15
|
+
UntypedSignal, UntypedWorkflow, WorkflowCancelOptions, WorkflowSignalOptions,
|
|
16
|
+
WorkflowStartOptions,
|
|
17
|
+
};
|
|
15
18
|
use temporalio_common::{
|
|
16
|
-
|
|
19
|
+
data_converters::{
|
|
20
|
+
GenericPayloadConverter, PayloadConverter, RawValue, SerializationContext,
|
|
21
|
+
SerializationContextData,
|
|
22
|
+
},
|
|
17
23
|
protos::{
|
|
18
24
|
coresdk::{
|
|
19
25
|
FromJsonPayloadExt,
|
|
@@ -35,15 +41,19 @@ use temporalio_common::{
|
|
|
35
41
|
},
|
|
36
42
|
worker::WorkerTaskTypes,
|
|
37
43
|
};
|
|
38
|
-
use
|
|
44
|
+
use temporalio_macros::{workflow, workflow_methods};
|
|
45
|
+
use temporalio_sdk::{
|
|
46
|
+
CancellableFuture, NexusOperationOptions, SyncWorkflowContext, WorkflowContext,
|
|
47
|
+
WorkflowContextView, WorkflowResult, WorkflowTermination,
|
|
48
|
+
};
|
|
49
|
+
use temporalio_sdk_core::PollError;
|
|
39
50
|
use tokio::{
|
|
40
51
|
join,
|
|
41
52
|
sync::{mpsc, watch},
|
|
42
53
|
};
|
|
43
|
-
use tokio_stream::StreamExt;
|
|
44
54
|
|
|
45
|
-
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
46
|
-
enum Outcome {
|
|
55
|
+
#[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
|
56
|
+
pub(crate) enum Outcome {
|
|
47
57
|
Succeed,
|
|
48
58
|
Fail,
|
|
49
59
|
Cancel,
|
|
@@ -51,6 +61,43 @@ enum Outcome {
|
|
|
51
61
|
Timeout,
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
#[workflow]
|
|
65
|
+
#[derive(Default)]
|
|
66
|
+
struct NexusBasicWf {
|
|
67
|
+
endpoint: String,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[workflow_methods]
|
|
71
|
+
impl NexusBasicWf {
|
|
72
|
+
#[init]
|
|
73
|
+
fn new(_ctx: &WorkflowContextView, endpoint: String) -> Self {
|
|
74
|
+
Self { endpoint }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[run]
|
|
78
|
+
pub(crate) async fn run(
|
|
79
|
+
ctx: &mut WorkflowContext<Self>,
|
|
80
|
+
) -> WorkflowResult<Result<NexusOperationResult, Failure>> {
|
|
81
|
+
match ctx
|
|
82
|
+
.start_nexus_operation(NexusOperationOptions {
|
|
83
|
+
endpoint: ctx.state(|wf| wf.endpoint.clone()),
|
|
84
|
+
service: "svc".to_string(),
|
|
85
|
+
operation: "op".to_string(),
|
|
86
|
+
schedule_to_close_timeout: Some(Duration::from_secs(3)),
|
|
87
|
+
..Default::default()
|
|
88
|
+
})
|
|
89
|
+
.await
|
|
90
|
+
{
|
|
91
|
+
Ok(started) => {
|
|
92
|
+
assert_eq!(started.operation_token, None);
|
|
93
|
+
let res = started.result().await;
|
|
94
|
+
Ok(Ok(res))
|
|
95
|
+
}
|
|
96
|
+
Err(failure) => Ok(Err(failure)),
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
54
101
|
#[rstest::rstest]
|
|
55
102
|
#[tokio::test]
|
|
56
103
|
async fn nexus_basic(
|
|
@@ -58,7 +105,7 @@ async fn nexus_basic(
|
|
|
58
105
|
) {
|
|
59
106
|
let wf_name = "nexus_basic";
|
|
60
107
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
61
|
-
starter.
|
|
108
|
+
starter.sdk_config.task_types = WorkerTaskTypes {
|
|
62
109
|
enable_workflows: true,
|
|
63
110
|
enable_local_activities: false,
|
|
64
111
|
enable_remote_activities: false,
|
|
@@ -69,31 +116,17 @@ async fn nexus_basic(
|
|
|
69
116
|
|
|
70
117
|
let endpoint = mk_nexus_endpoint(&mut starter).await;
|
|
71
118
|
|
|
72
|
-
worker.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
..Default::default()
|
|
82
|
-
})
|
|
83
|
-
.await
|
|
84
|
-
{
|
|
85
|
-
Ok(started) => {
|
|
86
|
-
assert_eq!(started.operation_token, None);
|
|
87
|
-
let res = started.result().await;
|
|
88
|
-
Ok(Ok(res).into())
|
|
89
|
-
}
|
|
90
|
-
Err(failure) => Ok(Err(failure).into()),
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
let wf_handle = starter.start_with_worker(wf_name, &mut worker).await;
|
|
119
|
+
worker.register_workflow::<NexusBasicWf>();
|
|
120
|
+
let wf_handle = worker
|
|
121
|
+
.submit_workflow(
|
|
122
|
+
NexusBasicWf::run,
|
|
123
|
+
endpoint.clone(),
|
|
124
|
+
starter.workflow_options.clone(),
|
|
125
|
+
)
|
|
126
|
+
.await
|
|
127
|
+
.unwrap();
|
|
95
128
|
|
|
96
|
-
let client = starter.get_client().await
|
|
129
|
+
let client = starter.get_client().await;
|
|
97
130
|
let nexus_task_handle = async {
|
|
98
131
|
let nt = core_worker.poll_nexus_task().await.unwrap().unwrap_task();
|
|
99
132
|
match outcome {
|
|
@@ -132,6 +165,7 @@ async fn nexus_basic(
|
|
|
132
165
|
core_worker
|
|
133
166
|
.complete_nexus_task(NexusTaskCompletion {
|
|
134
167
|
task_token: nt.task_token,
|
|
168
|
+
#[allow(deprecated)]
|
|
135
169
|
status: Some(nexus_task_completion::Status::Error(HandlerError {
|
|
136
170
|
error_type: "BAD_REQUEST".to_string(), // bad req is non-retryable
|
|
137
171
|
failure: Some(nexus::v1::Failure {
|
|
@@ -157,12 +191,13 @@ async fn nexus_basic(
|
|
|
157
191
|
});
|
|
158
192
|
|
|
159
193
|
let res = client
|
|
160
|
-
.
|
|
161
|
-
.
|
|
194
|
+
.get_workflow_handle::<UntypedWorkflow>(starter.get_task_queue().to_owned())
|
|
195
|
+
.get_result(Default::default())
|
|
162
196
|
.await
|
|
163
197
|
.unwrap();
|
|
164
|
-
let res =
|
|
165
|
-
.unwrap()
|
|
198
|
+
let res =
|
|
199
|
+
Result::<NexusOperationResult, Failure>::from_json_payload(res.payloads.first().unwrap())
|
|
200
|
+
.unwrap();
|
|
166
201
|
match outcome {
|
|
167
202
|
Outcome::Succeed => {
|
|
168
203
|
let p = assert_matches!(
|
|
@@ -194,6 +229,80 @@ async fn nexus_basic(
|
|
|
194
229
|
.unwrap();
|
|
195
230
|
}
|
|
196
231
|
|
|
232
|
+
#[workflow]
|
|
233
|
+
struct NexusAsyncWf {
|
|
234
|
+
endpoint: String,
|
|
235
|
+
schedule_to_close_timeout: Option<Duration>,
|
|
236
|
+
outcome: Outcome,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#[workflow_methods]
|
|
240
|
+
impl NexusAsyncWf {
|
|
241
|
+
#[init]
|
|
242
|
+
fn new(
|
|
243
|
+
_ctx: &WorkflowContextView,
|
|
244
|
+
(endpoint, schedule_to_close_timeout, outcome): (String, Option<Duration>, Outcome),
|
|
245
|
+
) -> Self {
|
|
246
|
+
Self {
|
|
247
|
+
endpoint,
|
|
248
|
+
schedule_to_close_timeout,
|
|
249
|
+
outcome,
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#[run]
|
|
254
|
+
pub(crate) async fn run(
|
|
255
|
+
ctx: &mut WorkflowContext<Self>,
|
|
256
|
+
) -> WorkflowResult<NexusOperationResult> {
|
|
257
|
+
let started = ctx.start_nexus_operation(NexusOperationOptions {
|
|
258
|
+
endpoint: ctx.state(|wf| wf.endpoint.clone()),
|
|
259
|
+
service: "svc".to_string(),
|
|
260
|
+
operation: "op".to_string(),
|
|
261
|
+
schedule_to_close_timeout: ctx.state(|wf| wf.schedule_to_close_timeout),
|
|
262
|
+
..Default::default()
|
|
263
|
+
});
|
|
264
|
+
if ctx.state(|wf| wf.outcome) == Outcome::CancelAfterRecordedBeforeStarted {
|
|
265
|
+
ctx.timer(Duration::from_millis(1)).await;
|
|
266
|
+
started.cancel();
|
|
267
|
+
}
|
|
268
|
+
let started = started.await.unwrap();
|
|
269
|
+
let result = started.result();
|
|
270
|
+
if matches!(ctx.state(|wf| wf.outcome), Outcome::Cancel) {
|
|
271
|
+
started.cancel();
|
|
272
|
+
started.cancel();
|
|
273
|
+
}
|
|
274
|
+
let res = result.await;
|
|
275
|
+
started.cancel();
|
|
276
|
+
Ok(res)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
#[workflow]
|
|
281
|
+
struct AsyncCompleter {
|
|
282
|
+
outcome: Outcome,
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
#[workflow_methods]
|
|
286
|
+
impl AsyncCompleter {
|
|
287
|
+
#[init]
|
|
288
|
+
fn new(_ctx: &WorkflowContextView, outcome: Outcome) -> Self {
|
|
289
|
+
Self { outcome }
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#[allow(dead_code)] // Started via untyped submitter handle
|
|
293
|
+
#[run]
|
|
294
|
+
pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
|
|
295
|
+
match ctx.state(|wf| wf.outcome) {
|
|
296
|
+
Outcome::Succeed => Ok("completed async".to_string()),
|
|
297
|
+
Outcome::Cancel | Outcome::CancelAfterRecordedBeforeStarted => {
|
|
298
|
+
ctx.cancelled().await;
|
|
299
|
+
Err(WorkflowTermination::Cancelled)
|
|
300
|
+
}
|
|
301
|
+
_ => Err(anyhow!("broken").into()),
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
197
306
|
#[rstest::rstest]
|
|
198
307
|
#[tokio::test]
|
|
199
308
|
async fn nexus_async(
|
|
@@ -208,7 +317,7 @@ async fn nexus_async(
|
|
|
208
317
|
) {
|
|
209
318
|
let wf_name = "nexus_async";
|
|
210
319
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
211
|
-
starter.
|
|
320
|
+
starter.sdk_config.task_types = WorkerTaskTypes {
|
|
212
321
|
enable_workflows: true,
|
|
213
322
|
enable_local_activities: false,
|
|
214
323
|
enable_remote_activities: false,
|
|
@@ -219,56 +328,29 @@ async fn nexus_async(
|
|
|
219
328
|
|
|
220
329
|
let endpoint = mk_nexus_endpoint(&mut starter).await;
|
|
221
330
|
let schedule_to_close_timeout = if outcome == Outcome::CancelAfterRecordedBeforeStarted {
|
|
222
|
-
// If we set this, it'll time out before we can cancel it.
|
|
223
331
|
None
|
|
224
332
|
} else {
|
|
225
333
|
Some(Duration::from_secs(5))
|
|
226
334
|
};
|
|
227
335
|
|
|
228
|
-
worker.
|
|
229
|
-
|
|
230
|
-
async move {
|
|
231
|
-
let started = ctx.start_nexus_operation(NexusOperationOptions {
|
|
232
|
-
endpoint,
|
|
233
|
-
service: "svc".to_string(),
|
|
234
|
-
operation: "op".to_string(),
|
|
235
|
-
schedule_to_close_timeout,
|
|
236
|
-
..Default::default()
|
|
237
|
-
});
|
|
238
|
-
if outcome == Outcome::CancelAfterRecordedBeforeStarted {
|
|
239
|
-
ctx.timer(Duration::from_millis(1)).await;
|
|
240
|
-
started.cancel(&ctx);
|
|
241
|
-
}
|
|
242
|
-
let started = started.await.unwrap();
|
|
243
|
-
let result = started.result();
|
|
244
|
-
if matches!(outcome, Outcome::Cancel) {
|
|
245
|
-
started.cancel(&ctx);
|
|
246
|
-
// Make sure double-cancel doesn't cause problems
|
|
247
|
-
started.cancel(&ctx);
|
|
248
|
-
}
|
|
249
|
-
let res = result.await;
|
|
250
|
-
// Make sure cancel after completion doesn't cause problems
|
|
251
|
-
started.cancel(&ctx);
|
|
252
|
-
Ok(res.into())
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
worker.register_wf(
|
|
256
|
-
"async_completer".to_owned(),
|
|
257
|
-
move |ctx: WfContext| async move {
|
|
258
|
-
match outcome {
|
|
259
|
-
Outcome::Succeed => Ok("completed async".into()),
|
|
260
|
-
Outcome::Cancel | Outcome::CancelAfterRecordedBeforeStarted => {
|
|
261
|
-
ctx.cancelled().await;
|
|
262
|
-
Ok(WfExitValue::Cancelled)
|
|
263
|
-
}
|
|
264
|
-
_ => bail!("broken"),
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
);
|
|
336
|
+
worker.register_workflow::<NexusAsyncWf>();
|
|
337
|
+
worker.register_workflow::<AsyncCompleter>();
|
|
268
338
|
let submitter = worker.get_submitter_handle();
|
|
269
|
-
let
|
|
339
|
+
let converter = PayloadConverter::default();
|
|
340
|
+
let ser_ctx = SerializationContext {
|
|
341
|
+
data: &SerializationContextData::Workflow,
|
|
342
|
+
converter: &converter,
|
|
343
|
+
};
|
|
344
|
+
let wf_handle = worker
|
|
345
|
+
.submit_workflow(
|
|
346
|
+
NexusAsyncWf::run,
|
|
347
|
+
(endpoint.clone(), schedule_to_close_timeout, outcome),
|
|
348
|
+
starter.workflow_options.clone(),
|
|
349
|
+
)
|
|
350
|
+
.await
|
|
351
|
+
.unwrap();
|
|
270
352
|
|
|
271
|
-
let client = starter.get_client().await
|
|
353
|
+
let client = starter.get_client().await;
|
|
272
354
|
let nexus_task_handle = async {
|
|
273
355
|
let mut nt = core_worker.poll_nexus_task().await.unwrap().unwrap_task();
|
|
274
356
|
// Verify request header key for timeout exists and is lowercase
|
|
@@ -311,23 +393,22 @@ async fn nexus_async(
|
|
|
311
393
|
|
|
312
394
|
// Start the workflow which will act like the nexus handler and complete the async
|
|
313
395
|
// operation
|
|
396
|
+
let payloads = vec![converter.to_payload(&ser_ctx, &outcome).unwrap()];
|
|
397
|
+
let task_queue = starter.get_task_queue().to_owned();
|
|
314
398
|
submitter
|
|
315
399
|
.submit_wf(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
completion_callbacks: vec![Callback {
|
|
400
|
+
AsyncCompleter::name(),
|
|
401
|
+
payloads,
|
|
402
|
+
WorkflowStartOptions::new(task_queue, completer_id.clone())
|
|
403
|
+
.completion_callbacks(vec![Callback {
|
|
321
404
|
variant: Some(callback::Variant::Nexus(callback::Nexus {
|
|
322
405
|
url: start_req.callback,
|
|
323
406
|
header: start_req.callback_header,
|
|
324
407
|
})),
|
|
325
408
|
links: links.clone(),
|
|
326
|
-
}]
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
..Default::default()
|
|
330
|
-
},
|
|
409
|
+
}])
|
|
410
|
+
.links(links)
|
|
411
|
+
.build(),
|
|
331
412
|
)
|
|
332
413
|
.await
|
|
333
414
|
.unwrap();
|
|
@@ -364,8 +445,13 @@ async fn nexus_async(
|
|
|
364
445
|
nt.request.unwrap().variant.unwrap(),
|
|
365
446
|
request::Variant::CancelOperation(_)
|
|
366
447
|
);
|
|
367
|
-
client
|
|
368
|
-
|
|
448
|
+
let handle = client.get_workflow_handle::<UntypedWorkflow>(completer_id);
|
|
449
|
+
handle
|
|
450
|
+
.cancel(
|
|
451
|
+
WorkflowCancelOptions::builder()
|
|
452
|
+
.reason("nexus cancel")
|
|
453
|
+
.build(),
|
|
454
|
+
)
|
|
369
455
|
.await
|
|
370
456
|
.unwrap();
|
|
371
457
|
core_worker
|
|
@@ -393,11 +479,11 @@ async fn nexus_async(
|
|
|
393
479
|
});
|
|
394
480
|
|
|
395
481
|
let res = client
|
|
396
|
-
.
|
|
397
|
-
.
|
|
482
|
+
.get_workflow_handle::<UntypedWorkflow>(starter.get_task_queue().to_owned())
|
|
483
|
+
.get_result(Default::default())
|
|
398
484
|
.await
|
|
399
485
|
.unwrap();
|
|
400
|
-
let res = NexusOperationResult::from_json_payload(
|
|
486
|
+
let res = NexusOperationResult::from_json_payload(res.payloads.first().unwrap()).unwrap();
|
|
401
487
|
match outcome {
|
|
402
488
|
Outcome::Succeed => {
|
|
403
489
|
let p = assert_matches!(
|
|
@@ -412,7 +498,7 @@ async fn nexus_async(
|
|
|
412
498
|
Some(nexus_operation_result::Status::Failed(f)) => f
|
|
413
499
|
);
|
|
414
500
|
assert_eq!(f.message, "nexus operation completed unsuccessfully");
|
|
415
|
-
assert_eq!(f.cause.unwrap().message, "broken");
|
|
501
|
+
assert_eq!(f.cause.unwrap().message, "Workflow execution error: broken");
|
|
416
502
|
}
|
|
417
503
|
Outcome::Cancel | Outcome::CancelAfterRecordedBeforeStarted => {
|
|
418
504
|
let f = assert_matches!(
|
|
@@ -436,11 +522,46 @@ async fn nexus_async(
|
|
|
436
522
|
.await
|
|
437
523
|
.unwrap();
|
|
438
524
|
}
|
|
525
|
+
#[workflow]
|
|
526
|
+
#[derive(Default)]
|
|
527
|
+
struct NexusCancelBeforeStartWf {
|
|
528
|
+
endpoint: String,
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
#[workflow_methods]
|
|
532
|
+
impl NexusCancelBeforeStartWf {
|
|
533
|
+
#[init]
|
|
534
|
+
fn new(_ctx: &WorkflowContextView, endpoint: String) -> Self {
|
|
535
|
+
Self { endpoint }
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
#[run]
|
|
539
|
+
pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
540
|
+
let started = ctx.start_nexus_operation(NexusOperationOptions {
|
|
541
|
+
endpoint: ctx.state(|wf| wf.endpoint.clone()),
|
|
542
|
+
service: "svc".to_string(),
|
|
543
|
+
operation: "op".to_string(),
|
|
544
|
+
..Default::default()
|
|
545
|
+
});
|
|
546
|
+
started.cancel();
|
|
547
|
+
let res = started.await.unwrap_err();
|
|
548
|
+
assert_eq!(res.message, "Nexus Operation cancelled before scheduled");
|
|
549
|
+
if let FailureInfo::NexusOperationExecutionFailureInfo(fi) = res.failure_info.unwrap() {
|
|
550
|
+
assert_eq!(fi.endpoint, ctx.state(|wf| wf.endpoint.clone()));
|
|
551
|
+
assert_eq!(fi.service, "svc");
|
|
552
|
+
assert_eq!(fi.operation, "op");
|
|
553
|
+
} else {
|
|
554
|
+
panic!("unexpected failure info");
|
|
555
|
+
}
|
|
556
|
+
Ok(())
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
439
560
|
#[tokio::test]
|
|
440
561
|
async fn nexus_cancel_before_start() {
|
|
441
562
|
let wf_name = "nexus_cancel_before_start";
|
|
442
563
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
443
|
-
starter.
|
|
564
|
+
starter.sdk_config.task_types = WorkerTaskTypes {
|
|
444
565
|
enable_workflows: true,
|
|
445
566
|
enable_local_activities: false,
|
|
446
567
|
enable_remote_activities: false,
|
|
@@ -450,29 +571,15 @@ async fn nexus_cancel_before_start() {
|
|
|
450
571
|
|
|
451
572
|
let endpoint = mk_nexus_endpoint(&mut starter).await;
|
|
452
573
|
|
|
453
|
-
worker.
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
started.cancel(&ctx);
|
|
463
|
-
let res = started.await.unwrap_err();
|
|
464
|
-
assert_eq!(res.message, "Nexus Operation cancelled before scheduled");
|
|
465
|
-
if let FailureInfo::NexusOperationExecutionFailureInfo(fi) = res.failure_info.unwrap() {
|
|
466
|
-
assert_eq!(fi.endpoint, endpoint);
|
|
467
|
-
assert_eq!(fi.service, "svc");
|
|
468
|
-
assert_eq!(fi.operation, "op");
|
|
469
|
-
} else {
|
|
470
|
-
panic!("unexpected failure info");
|
|
471
|
-
}
|
|
472
|
-
Ok(().into())
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
let handle = starter.start_with_worker(wf_name, &mut worker).await;
|
|
574
|
+
worker.register_workflow::<NexusCancelBeforeStartWf>();
|
|
575
|
+
let handle = worker
|
|
576
|
+
.submit_workflow(
|
|
577
|
+
NexusCancelBeforeStartWf::run,
|
|
578
|
+
endpoint,
|
|
579
|
+
starter.workflow_options.clone(),
|
|
580
|
+
)
|
|
581
|
+
.await
|
|
582
|
+
.unwrap();
|
|
476
583
|
|
|
477
584
|
worker.run_until_done().await.unwrap();
|
|
478
585
|
|
|
@@ -482,53 +589,71 @@ async fn nexus_cancel_before_start() {
|
|
|
482
589
|
.unwrap();
|
|
483
590
|
}
|
|
484
591
|
|
|
592
|
+
#[workflow]
|
|
593
|
+
#[derive(Default)]
|
|
594
|
+
struct NexusMustCompleteTaskWf {
|
|
595
|
+
endpoint: String,
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
#[workflow_methods]
|
|
599
|
+
impl NexusMustCompleteTaskWf {
|
|
600
|
+
#[init]
|
|
601
|
+
fn new(_ctx: &WorkflowContextView, endpoint: String) -> Self {
|
|
602
|
+
Self { endpoint }
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
#[run]
|
|
606
|
+
pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
607
|
+
// We just need to create the command, not await it.
|
|
608
|
+
drop(ctx.start_nexus_operation(NexusOperationOptions {
|
|
609
|
+
endpoint: ctx.state(|wf| wf.endpoint.clone()),
|
|
610
|
+
service: "svc".to_string(),
|
|
611
|
+
operation: "op".to_string(),
|
|
612
|
+
..Default::default()
|
|
613
|
+
}));
|
|
614
|
+
// Workflow completes right away, only having scheduled the operation. We need a timer
|
|
615
|
+
// to make sure the nexus task actually gets scheduled.
|
|
616
|
+
ctx.timer(Duration::from_millis(1)).await;
|
|
617
|
+
// started.await.unwrap();
|
|
618
|
+
Ok(())
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
485
622
|
#[rstest::rstest]
|
|
486
623
|
#[tokio::test]
|
|
487
624
|
async fn nexus_must_complete_task_to_shutdown(#[values(true, false)] use_grace_period: bool) {
|
|
488
625
|
let wf_name = "nexus_must_complete_task_to_shutdown";
|
|
489
626
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
490
|
-
starter.
|
|
627
|
+
starter.sdk_config.task_types = WorkerTaskTypes {
|
|
491
628
|
enable_workflows: true,
|
|
492
629
|
enable_local_activities: false,
|
|
493
630
|
enable_remote_activities: false,
|
|
494
631
|
enable_nexus: true,
|
|
495
632
|
};
|
|
496
633
|
if use_grace_period {
|
|
497
|
-
starter.
|
|
634
|
+
starter.sdk_config.graceful_shutdown_period = Some(Duration::from_millis(500));
|
|
498
635
|
}
|
|
499
636
|
let mut worker = starter.worker().await;
|
|
500
637
|
let core_worker = starter.get_worker().await;
|
|
501
638
|
|
|
502
639
|
let endpoint = mk_nexus_endpoint(&mut starter).await;
|
|
503
640
|
|
|
504
|
-
worker.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}));
|
|
514
|
-
// Workflow completes right away, only having scheduled the operation. We need a timer
|
|
515
|
-
// to make sure the nexus task actually gets scheduled.
|
|
516
|
-
ctx.timer(Duration::from_millis(1)).await;
|
|
517
|
-
// started.await.unwrap();
|
|
518
|
-
Ok(().into())
|
|
519
|
-
}
|
|
520
|
-
});
|
|
521
|
-
let handle = starter.start_with_worker(wf_name, &mut worker).await;
|
|
641
|
+
worker.register_workflow::<NexusMustCompleteTaskWf>();
|
|
642
|
+
let handle = worker
|
|
643
|
+
.submit_workflow(
|
|
644
|
+
NexusMustCompleteTaskWf::run,
|
|
645
|
+
endpoint,
|
|
646
|
+
starter.workflow_options.clone(),
|
|
647
|
+
)
|
|
648
|
+
.await
|
|
649
|
+
.unwrap();
|
|
522
650
|
let (complete_order_tx, mut complete_order_rx) = mpsc::unbounded_channel();
|
|
523
651
|
|
|
524
652
|
let task_handle = async {
|
|
525
653
|
// Should get the nexus task first
|
|
526
654
|
let nt = core_worker.poll_nexus_task().await.unwrap().unwrap_task();
|
|
527
655
|
// The workflow will complete
|
|
528
|
-
handle
|
|
529
|
-
.get_workflow_result(Default::default())
|
|
530
|
-
.await
|
|
531
|
-
.unwrap();
|
|
656
|
+
handle.get_result(Default::default()).await.unwrap();
|
|
532
657
|
if use_grace_period {
|
|
533
658
|
// Wait for cancel to be sent
|
|
534
659
|
let nt = core_worker.poll_nexus_task().await.unwrap();
|
|
@@ -544,6 +669,7 @@ async fn nexus_must_complete_task_to_shutdown(#[values(true, false)] use_grace_p
|
|
|
544
669
|
core_worker
|
|
545
670
|
.complete_nexus_task(NexusTaskCompletion {
|
|
546
671
|
task_token: nt.task_token,
|
|
672
|
+
#[allow(deprecated)]
|
|
547
673
|
status: Some(nexus_task_completion::Status::Error(HandlerError {
|
|
548
674
|
error_type: "BAD_REQUEST".to_string(), // bad req is non-retryable
|
|
549
675
|
failure: Some(nexus::v1::Failure {
|
|
@@ -577,6 +703,89 @@ async fn nexus_must_complete_task_to_shutdown(#[values(true, false)] use_grace_p
|
|
|
577
703
|
.unwrap();
|
|
578
704
|
}
|
|
579
705
|
|
|
706
|
+
#[workflow]
|
|
707
|
+
struct NexusCancellationCallerWf {
|
|
708
|
+
endpoint: String,
|
|
709
|
+
schedule_to_close_timeout: Option<Duration>,
|
|
710
|
+
cancellation_type: NexusOperationCancellationType,
|
|
711
|
+
caller_op_future_tx: watch::Sender<bool>,
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
#[workflow_methods(factory_only)]
|
|
715
|
+
impl NexusCancellationCallerWf {
|
|
716
|
+
#[run(name = "nexus_cancellation_types")]
|
|
717
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<NexusOperationResult> {
|
|
718
|
+
let options = NexusOperationOptions {
|
|
719
|
+
endpoint: ctx.state(|wf| wf.endpoint.clone()),
|
|
720
|
+
service: "svc".to_string(),
|
|
721
|
+
operation: "op".to_string(),
|
|
722
|
+
schedule_to_close_timeout: ctx.state(|wf| wf.schedule_to_close_timeout),
|
|
723
|
+
cancellation_type: Some(ctx.state(|wf| wf.cancellation_type)),
|
|
724
|
+
..Default::default()
|
|
725
|
+
};
|
|
726
|
+
let started = ctx.start_nexus_operation(options);
|
|
727
|
+
let started = started.await.unwrap();
|
|
728
|
+
let result = started.result();
|
|
729
|
+
started.cancel();
|
|
730
|
+
started.cancel();
|
|
731
|
+
|
|
732
|
+
let res = result.await;
|
|
733
|
+
ctx.state(|wf| wf.caller_op_future_tx.send(true).unwrap());
|
|
734
|
+
|
|
735
|
+
// Make sure cancel after op completion doesn't cause problems
|
|
736
|
+
started.cancel();
|
|
737
|
+
|
|
738
|
+
// We need to wait slightly so that the workflow is not complete at the same time
|
|
739
|
+
// cancellation is invoked. If it does, the caller workflow will close and the server
|
|
740
|
+
// won't attempt to send the cancellation to the handler
|
|
741
|
+
ctx.timer(Duration::from_millis(1)).await;
|
|
742
|
+
Ok(res)
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
#[workflow]
|
|
747
|
+
struct AsyncCompleterWf {
|
|
748
|
+
cancellation_type: NexusOperationCancellationType,
|
|
749
|
+
cancellation_wait_happened: Arc<AtomicBool>,
|
|
750
|
+
cancellation_tx: watch::Sender<bool>,
|
|
751
|
+
handler_exited_tx: watch::Sender<bool>,
|
|
752
|
+
proceed_signal_received: bool,
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
#[workflow_methods(factory_only)]
|
|
756
|
+
impl AsyncCompleterWf {
|
|
757
|
+
#[run(name = "async_completer")]
|
|
758
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
759
|
+
// Wait for cancellation
|
|
760
|
+
ctx.cancelled().await;
|
|
761
|
+
ctx.state(|wf| wf.cancellation_tx.send(true).unwrap());
|
|
762
|
+
|
|
763
|
+
if ctx.state(|wf| wf.cancellation_type)
|
|
764
|
+
== NexusOperationCancellationType::WaitCancellationCompleted
|
|
765
|
+
{
|
|
766
|
+
ctx.wait_condition(|wf| wf.cancellation_wait_happened.load(Ordering::Relaxed))
|
|
767
|
+
.await;
|
|
768
|
+
} else if ctx.state(|wf| wf.cancellation_type)
|
|
769
|
+
== NexusOperationCancellationType::WaitCancellationRequested
|
|
770
|
+
{
|
|
771
|
+
// For WAIT_REQUESTED, wait until the caller nexus op future has been resolved. This
|
|
772
|
+
// allows the test to verify that it resolved due to
|
|
773
|
+
// NexusOperationCancelRequestCompleted (written after cancel handler responds)
|
|
774
|
+
// rather than NexusOperationCanceled (written after handler workflow completes as
|
|
775
|
+
// cancelled).
|
|
776
|
+
ctx.wait_condition(|wf| wf.proceed_signal_received).await;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
ctx.state(|wf| wf.handler_exited_tx.send(true).unwrap());
|
|
780
|
+
Err(WorkflowTermination::Cancelled)
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
#[signal(name = "proceed-to-exit")]
|
|
784
|
+
fn handle_proceed_signal(&mut self, _ctx: &mut SyncWorkflowContext<Self>) {
|
|
785
|
+
self.proceed_signal_received = true;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
580
789
|
#[rstest::rstest]
|
|
581
790
|
#[tokio::test]
|
|
582
791
|
async fn nexus_cancellation_types(
|
|
@@ -590,7 +799,7 @@ async fn nexus_cancellation_types(
|
|
|
590
799
|
) {
|
|
591
800
|
let wf_name = "nexus_cancellation_types";
|
|
592
801
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
593
|
-
starter.
|
|
802
|
+
starter.sdk_config.task_types = WorkerTaskTypes {
|
|
594
803
|
enable_workflows: true,
|
|
595
804
|
enable_local_activities: false,
|
|
596
805
|
enable_remote_activities: false,
|
|
@@ -603,72 +812,35 @@ async fn nexus_cancellation_types(
|
|
|
603
812
|
let schedule_to_close_timeout = Some(Duration::from_secs(5));
|
|
604
813
|
|
|
605
814
|
let (caller_op_future_tx, caller_op_future_rx) = watch::channel(false);
|
|
606
|
-
worker.
|
|
815
|
+
worker.register_workflow_with_factory({
|
|
607
816
|
let endpoint = endpoint.clone();
|
|
608
817
|
let caller_op_future_tx = caller_op_future_tx.clone();
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
schedule_to_close_timeout,
|
|
615
|
-
cancellation_type: Some(cancellation_type),
|
|
616
|
-
..Default::default()
|
|
617
|
-
};
|
|
618
|
-
let started = ctx.start_nexus_operation(options);
|
|
619
|
-
let started = started.await.unwrap();
|
|
620
|
-
let result = started.result();
|
|
621
|
-
started.cancel(&ctx);
|
|
622
|
-
started.cancel(&ctx);
|
|
623
|
-
|
|
624
|
-
let res = result.await;
|
|
625
|
-
caller_op_future_tx.send(true).unwrap();
|
|
626
|
-
|
|
627
|
-
// Make sure cancel after op completion doesn't cause problems
|
|
628
|
-
started.cancel(&ctx);
|
|
629
|
-
|
|
630
|
-
// We need to wait slightly so that the workflow is not complete at the same time
|
|
631
|
-
// cancellation is invoked. If it does, the caller workflow will close and the server
|
|
632
|
-
// won't attempt to send the cancellation to the handler
|
|
633
|
-
ctx.timer(Duration::from_millis(1)).await;
|
|
634
|
-
Ok(res.into())
|
|
818
|
+
move || NexusCancellationCallerWf {
|
|
819
|
+
endpoint: endpoint.clone(),
|
|
820
|
+
schedule_to_close_timeout,
|
|
821
|
+
cancellation_type,
|
|
822
|
+
caller_op_future_tx: caller_op_future_tx.clone(),
|
|
635
823
|
}
|
|
636
824
|
});
|
|
637
825
|
|
|
638
826
|
let cancellation_wait_happened = Arc::new(AtomicBool::new(false));
|
|
639
|
-
let cancellation_wait_happened_clone = cancellation_wait_happened.clone();
|
|
640
827
|
let (cancellation_tx, mut cancellation_rx) = watch::channel(false);
|
|
641
828
|
let (handler_exited_tx, mut handler_exited_rx) = watch::channel(false);
|
|
642
|
-
worker.
|
|
829
|
+
worker.register_workflow_with_factory({
|
|
830
|
+
let cancellation_wait_happened = cancellation_wait_happened.clone();
|
|
643
831
|
let cancellation_tx = cancellation_tx.clone();
|
|
644
|
-
let cancellation_wait_happened = cancellation_wait_happened_clone.clone();
|
|
645
832
|
let handler_exited_tx = handler_exited_tx.clone();
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
cancellation_tx.
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
ctx.wait_condition(|| cancellation_wait_happened.load(Ordering::Relaxed))
|
|
653
|
-
.await;
|
|
654
|
-
} else if cancellation_type == NexusOperationCancellationType::WaitCancellationRequested
|
|
655
|
-
{
|
|
656
|
-
// For WAIT_REQUESTED, wait until the caller nexus op future has been resolved. This
|
|
657
|
-
// allows the test to verify that it resolved due to
|
|
658
|
-
// NexusOperationCancelRequestCompleted (written after cancel handler responds)
|
|
659
|
-
// rather than NexusOperationCanceled (written after handler workflow completes as
|
|
660
|
-
// cancelled).
|
|
661
|
-
let mut signal_chan = ctx.make_signal_channel("proceed-to-exit");
|
|
662
|
-
signal_chan.next().await;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
handler_exited_tx.send(true).unwrap();
|
|
666
|
-
Ok(WfExitValue::<()>::Cancelled)
|
|
833
|
+
move || AsyncCompleterWf {
|
|
834
|
+
cancellation_type,
|
|
835
|
+
cancellation_wait_happened: cancellation_wait_happened.clone(),
|
|
836
|
+
cancellation_tx: cancellation_tx.clone(),
|
|
837
|
+
handler_exited_tx: handler_exited_tx.clone(),
|
|
838
|
+
proceed_signal_received: false,
|
|
667
839
|
}
|
|
668
840
|
});
|
|
669
841
|
let submitter = worker.get_submitter_handle();
|
|
670
842
|
let wf_handle = starter.start_with_worker(wf_name, &mut worker).await;
|
|
671
|
-
let client = starter.get_client().await
|
|
843
|
+
let client = starter.get_client().await;
|
|
672
844
|
let (handler_wf_id_tx, mut handler_wf_id_rx) = tokio::sync::oneshot::channel();
|
|
673
845
|
let completer_id = &format!("completer-{}", rand_6_chars());
|
|
674
846
|
let nexus_task_handle = async {
|
|
@@ -687,23 +859,21 @@ async fn nexus_cancellation_types(
|
|
|
687
859
|
|
|
688
860
|
// Start the workflow which will act like the nexus handler and complete the async
|
|
689
861
|
// operation
|
|
862
|
+
let task_queue = starter.get_task_queue().to_owned();
|
|
690
863
|
submitter
|
|
691
864
|
.submit_wf(
|
|
692
|
-
completer_id.clone(),
|
|
693
865
|
"async_completer",
|
|
694
866
|
vec![],
|
|
695
|
-
|
|
696
|
-
completion_callbacks
|
|
867
|
+
WorkflowStartOptions::new(task_queue, completer_id.clone())
|
|
868
|
+
.completion_callbacks(vec![Callback {
|
|
697
869
|
variant: Some(callback::Variant::Nexus(callback::Nexus {
|
|
698
870
|
url: start_req.callback,
|
|
699
871
|
header: start_req.callback_header,
|
|
700
872
|
})),
|
|
701
873
|
links: links.clone(),
|
|
702
|
-
}]
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
..Default::default()
|
|
706
|
-
},
|
|
874
|
+
}])
|
|
875
|
+
.links(links)
|
|
876
|
+
.build(),
|
|
707
877
|
)
|
|
708
878
|
.await
|
|
709
879
|
.unwrap();
|
|
@@ -737,10 +907,7 @@ async fn nexus_cancellation_types(
|
|
|
737
907
|
assert!(!*caller_op_future_rx.borrow());
|
|
738
908
|
}
|
|
739
909
|
NexusOperationCancellationType::Abandon | NexusOperationCancellationType::TryCancel => {
|
|
740
|
-
wf_handle
|
|
741
|
-
.get_workflow_result(Default::default())
|
|
742
|
-
.await
|
|
743
|
-
.unwrap();
|
|
910
|
+
wf_handle.get_result(Default::default()).await.unwrap();
|
|
744
911
|
// The nexus op future should have been resolved
|
|
745
912
|
assert!(*caller_op_future_rx.borrow())
|
|
746
913
|
}
|
|
@@ -753,12 +920,12 @@ async fn nexus_cancellation_types(
|
|
|
753
920
|
nt.request.unwrap().variant.unwrap(),
|
|
754
921
|
request::Variant::CancelOperation(_)
|
|
755
922
|
);
|
|
756
|
-
client
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
923
|
+
let handle = client.get_workflow_handle::<UntypedWorkflow>(completer_id.to_string());
|
|
924
|
+
handle
|
|
925
|
+
.cancel(
|
|
926
|
+
WorkflowCancelOptions::builder()
|
|
927
|
+
.reason("nexus cancel")
|
|
928
|
+
.build(),
|
|
762
929
|
)
|
|
763
930
|
.await
|
|
764
931
|
.unwrap();
|
|
@@ -787,18 +954,14 @@ async fn nexus_cancellation_types(
|
|
|
787
954
|
// Send a signal just to wake up the workflow so it'll check the condition
|
|
788
955
|
// (it may already have completed, so ignore the result)
|
|
789
956
|
let _ = client
|
|
790
|
-
.
|
|
791
|
-
|
|
792
|
-
""
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
None,
|
|
957
|
+
.get_workflow_handle::<UntypedWorkflow>(completer_id.to_string())
|
|
958
|
+
.signal(
|
|
959
|
+
UntypedSignal::new("wakeupdude"),
|
|
960
|
+
RawValue::empty(),
|
|
961
|
+
WorkflowSignalOptions::default(),
|
|
796
962
|
)
|
|
797
963
|
.await;
|
|
798
|
-
wf_handle
|
|
799
|
-
.get_workflow_result(Default::default())
|
|
800
|
-
.await
|
|
801
|
-
.unwrap();
|
|
964
|
+
wf_handle.get_result(Default::default()).await.unwrap();
|
|
802
965
|
assert!(*caller_op_future_rx.borrow());
|
|
803
966
|
}
|
|
804
967
|
|
|
@@ -827,12 +990,11 @@ async fn nexus_cancellation_types(
|
|
|
827
990
|
.try_recv()
|
|
828
991
|
.expect("Should have received handler workflow ID");
|
|
829
992
|
client
|
|
830
|
-
.
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
None,
|
|
993
|
+
.get_workflow_handle::<async_completer_wf::Run>(handler_wf_id)
|
|
994
|
+
.signal(
|
|
995
|
+
AsyncCompleterWf::handle_proceed_signal,
|
|
996
|
+
(),
|
|
997
|
+
WorkflowSignalOptions::default(),
|
|
836
998
|
)
|
|
837
999
|
.await
|
|
838
1000
|
.unwrap();
|
|
@@ -845,10 +1007,7 @@ async fn nexus_cancellation_types(
|
|
|
845
1007
|
nexus_task_handle,
|
|
846
1008
|
async { worker.inner_mut().run().await.unwrap() },
|
|
847
1009
|
async {
|
|
848
|
-
wf_handle
|
|
849
|
-
.get_workflow_result(Default::default())
|
|
850
|
-
.await
|
|
851
|
-
.unwrap();
|
|
1010
|
+
wf_handle.get_result(Default::default()).await.unwrap();
|
|
852
1011
|
if cancellation_type == NexusOperationCancellationType::TryCancel {
|
|
853
1012
|
cancellation_rx.changed().await.unwrap();
|
|
854
1013
|
}
|
|
@@ -871,11 +1030,11 @@ async fn nexus_cancellation_types(
|
|
|
871
1030
|
}
|
|
872
1031
|
|
|
873
1032
|
let res = client
|
|
874
|
-
.
|
|
875
|
-
.
|
|
1033
|
+
.get_workflow_handle::<UntypedWorkflow>(starter.get_task_queue().to_owned())
|
|
1034
|
+
.get_result(Default::default())
|
|
876
1035
|
.await
|
|
877
1036
|
.unwrap();
|
|
878
|
-
let res = NexusOperationResult::from_json_payload(
|
|
1037
|
+
let res = NexusOperationResult::from_json_payload(res.payloads.first().unwrap()).unwrap();
|
|
879
1038
|
|
|
880
1039
|
match cancellation_type {
|
|
881
1040
|
NexusOperationCancellationType::Abandon | NexusOperationCancellationType::TryCancel => {
|