@temporalio/core-bridge 1.15.0 → 1.16.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 +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 +16 -3
- 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 +340 -188
- 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 +15 -18
- 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
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
use crate::common::{
|
|
1
|
+
use crate::common::{
|
|
2
|
+
CoreWfStarter, WorkflowHandleExt, activity_functions::StdActivities, mock_sdk, mock_sdk_cfg,
|
|
3
|
+
};
|
|
2
4
|
use std::{
|
|
3
|
-
sync::
|
|
5
|
+
sync::{
|
|
6
|
+
Arc,
|
|
7
|
+
atomic::{AtomicBool, AtomicUsize, Ordering},
|
|
8
|
+
},
|
|
4
9
|
time::Duration,
|
|
5
10
|
};
|
|
6
|
-
use temporalio_client::
|
|
11
|
+
use temporalio_client::WorkflowStartOptions;
|
|
7
12
|
use temporalio_common::{
|
|
8
13
|
protos::{
|
|
9
|
-
|
|
14
|
+
TestHistoryBuilder, canned_histories,
|
|
10
15
|
coresdk::AsJsonPayloadExt,
|
|
11
16
|
temporal::api::{
|
|
12
17
|
enums::v1::{EventType, WorkflowTaskFailedCause},
|
|
@@ -15,85 +20,121 @@ use temporalio_common::{
|
|
|
15
20
|
},
|
|
16
21
|
worker::WorkerTaskTypes,
|
|
17
22
|
};
|
|
23
|
+
use temporalio_macros::{workflow, workflow_methods};
|
|
18
24
|
use temporalio_sdk::{
|
|
19
|
-
|
|
20
|
-
WorkflowResult,
|
|
25
|
+
ActivityOptions, ChildWorkflowOptions, LocalActivityOptions, WorkflowContext, WorkflowResult,
|
|
21
26
|
};
|
|
22
27
|
use temporalio_sdk_core::{
|
|
23
28
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
24
29
|
test_help::{CoreInternalFlags, MockPollCfg, ResponseType, mock_worker_client},
|
|
25
30
|
};
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
#[workflow]
|
|
33
|
+
pub(crate) struct TimerWfNondeterministic {
|
|
34
|
+
run_ct: Arc<AtomicUsize>,
|
|
35
|
+
}
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
#[workflow_methods(factory_only)]
|
|
38
|
+
impl TimerWfNondeterministic {
|
|
39
|
+
#[run]
|
|
40
|
+
pub(crate) async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
41
|
+
let run_ct = ctx.state(|wf| wf.run_ct.fetch_add(1, Ordering::Relaxed));
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
panic!("dying on purpose");
|
|
43
|
+
match run_ct {
|
|
44
|
+
1 | 3 => {
|
|
45
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
46
|
+
if run_ct == 1 {
|
|
47
|
+
panic!("dying on purpose");
|
|
48
|
+
}
|
|
39
49
|
}
|
|
50
|
+
2 => {
|
|
51
|
+
ctx.start_activity(StdActivities::default, (), ActivityOptions::default())
|
|
52
|
+
.await
|
|
53
|
+
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
54
|
+
}
|
|
55
|
+
_ => panic!("Ran too many times"),
|
|
40
56
|
}
|
|
41
|
-
|
|
42
|
-
// On the second attempt we should cause a nondeterminism error
|
|
43
|
-
ctx.activity(ActivityOptions {
|
|
44
|
-
activity_type: "whatever".to_string(),
|
|
45
|
-
..Default::default()
|
|
46
|
-
})
|
|
47
|
-
.await;
|
|
48
|
-
}
|
|
49
|
-
_ => panic!("Ran too many times"),
|
|
57
|
+
Ok(())
|
|
50
58
|
}
|
|
51
|
-
Ok(().into())
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
#[tokio::test]
|
|
55
62
|
async fn test_determinism_error_then_recovers() {
|
|
56
63
|
let wf_name = "test_determinism_error_then_recovers";
|
|
57
64
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
58
|
-
starter.
|
|
65
|
+
starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
|
|
59
66
|
let mut worker = starter.worker().await;
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
let run_ct = Arc::new(AtomicUsize::new(1));
|
|
69
|
+
let run_ct_clone = run_ct.clone();
|
|
70
|
+
worker.register_workflow_with_factory(move || TimerWfNondeterministic {
|
|
71
|
+
run_ct: run_ct_clone.clone(),
|
|
72
|
+
});
|
|
73
|
+
let task_queue = starter.get_task_queue().to_owned();
|
|
74
|
+
worker
|
|
75
|
+
.submit_workflow(
|
|
76
|
+
TimerWfNondeterministic::run,
|
|
77
|
+
(),
|
|
78
|
+
WorkflowStartOptions::new(task_queue, starter.get_task_queue().to_owned()).build(),
|
|
79
|
+
)
|
|
80
|
+
.await
|
|
81
|
+
.unwrap();
|
|
63
82
|
worker.run_until_done().await.unwrap();
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
assert_eq!(run_ct.load(Ordering::Relaxed), 4);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#[workflow]
|
|
87
|
+
struct TaskFailReplayWf {
|
|
88
|
+
did_fail: Arc<AtomicBool>,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[workflow_methods(factory_only)]
|
|
92
|
+
impl TaskFailReplayWf {
|
|
93
|
+
#[run]
|
|
94
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
95
|
+
if ctx.state(|wf| wf.did_fail.load(Ordering::Relaxed)) {
|
|
96
|
+
assert!(ctx.is_replaying());
|
|
97
|
+
}
|
|
98
|
+
let _ = ctx
|
|
99
|
+
.start_activity(
|
|
100
|
+
StdActivities::echo,
|
|
101
|
+
"hi!".to_string(),
|
|
102
|
+
ActivityOptions {
|
|
103
|
+
start_to_close_timeout: Some(Duration::from_secs(2)),
|
|
104
|
+
..Default::default()
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
.await;
|
|
108
|
+
if !ctx.state(|wf| wf.did_fail.load(Ordering::Relaxed)) {
|
|
109
|
+
ctx.state(|wf| wf.did_fail.store(true, Ordering::Relaxed));
|
|
110
|
+
panic!("Die on purpose");
|
|
111
|
+
}
|
|
112
|
+
Ok(())
|
|
113
|
+
}
|
|
66
114
|
}
|
|
67
115
|
|
|
68
116
|
#[tokio::test]
|
|
69
117
|
async fn task_fail_causes_replay_unset_too_soon() {
|
|
70
118
|
let wf_name = "task_fail_causes_replay_unset_too_soon";
|
|
71
119
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
120
|
+
starter.sdk_config.register_activities(StdActivities);
|
|
72
121
|
let mut worker = starter.worker().await;
|
|
73
122
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
ctx.activity(ActivityOptions {
|
|
80
|
-
activity_type: "echo".to_string(),
|
|
81
|
-
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
82
|
-
start_to_close_timeout: Some(Duration::from_secs(2)),
|
|
83
|
-
..Default::default()
|
|
84
|
-
})
|
|
85
|
-
.await;
|
|
86
|
-
if !DID_FAIL.load(Ordering::Relaxed) {
|
|
87
|
-
DID_FAIL.store(true, Ordering::Relaxed);
|
|
88
|
-
panic!("Die on purpose");
|
|
89
|
-
}
|
|
90
|
-
Ok(().into())
|
|
91
|
-
});
|
|
92
|
-
worker.register_activity("echo", |_ctx: ActContext, echo_me: String| async move {
|
|
93
|
-
Ok(echo_me)
|
|
123
|
+
let did_fail = Arc::new(AtomicBool::new(false));
|
|
124
|
+
let did_fail_clone = did_fail.clone();
|
|
125
|
+
worker.register_workflow_with_factory(move || TaskFailReplayWf {
|
|
126
|
+
did_fail: did_fail_clone.clone(),
|
|
94
127
|
});
|
|
95
128
|
|
|
96
|
-
let
|
|
129
|
+
let task_queue = starter.get_task_queue().to_owned();
|
|
130
|
+
let handle = worker
|
|
131
|
+
.submit_workflow(
|
|
132
|
+
TaskFailReplayWf::run,
|
|
133
|
+
(),
|
|
134
|
+
WorkflowStartOptions::new(task_queue, starter.get_task_queue().to_owned()).build(),
|
|
135
|
+
)
|
|
136
|
+
.await
|
|
137
|
+
.unwrap();
|
|
97
138
|
|
|
98
139
|
worker.run_until_done().await.unwrap();
|
|
99
140
|
handle
|
|
@@ -102,17 +143,27 @@ async fn task_fail_causes_replay_unset_too_soon() {
|
|
|
102
143
|
.unwrap();
|
|
103
144
|
}
|
|
104
145
|
|
|
105
|
-
|
|
106
|
-
|
|
146
|
+
#[workflow]
|
|
147
|
+
struct TimerWfFailsOnce {
|
|
148
|
+
did_fail: Arc<AtomicBool>,
|
|
149
|
+
}
|
|
107
150
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
151
|
+
#[workflow_methods(factory_only)]
|
|
152
|
+
impl TimerWfFailsOnce {
|
|
153
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
154
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
155
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
156
|
+
if ctx
|
|
157
|
+
.state(|wf| {
|
|
158
|
+
wf.did_fail
|
|
159
|
+
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
|
160
|
+
})
|
|
161
|
+
.is_ok()
|
|
162
|
+
{
|
|
163
|
+
panic!("Ahh");
|
|
164
|
+
}
|
|
165
|
+
Ok(())
|
|
114
166
|
}
|
|
115
|
-
Ok(().into())
|
|
116
167
|
}
|
|
117
168
|
|
|
118
169
|
/// Verifies that workflow panics (which in this case the Rust SDK turns into workflow activation
|
|
@@ -135,19 +186,39 @@ async fn test_panic_wf_task_rejected_properly() {
|
|
|
135
186
|
});
|
|
136
187
|
let mut worker = mock_sdk(mh);
|
|
137
188
|
|
|
138
|
-
|
|
189
|
+
let did_fail = Arc::new(AtomicBool::new(false));
|
|
190
|
+
worker.register_workflow_with_factory(move || TimerWfFailsOnce {
|
|
191
|
+
did_fail: did_fail.clone(),
|
|
192
|
+
});
|
|
193
|
+
let task_queue = "fake_tq".to_owned();
|
|
139
194
|
worker
|
|
140
195
|
.submit_wf(
|
|
141
|
-
wf_id.to_owned(),
|
|
142
196
|
wf_type.to_owned(),
|
|
143
197
|
vec![],
|
|
144
|
-
|
|
198
|
+
WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
|
|
145
199
|
)
|
|
146
200
|
.await
|
|
147
201
|
.unwrap();
|
|
148
202
|
worker.run_until_done().await.unwrap();
|
|
149
203
|
}
|
|
150
204
|
|
|
205
|
+
#[workflow]
|
|
206
|
+
struct NondeterministicTimerWf {
|
|
207
|
+
started_count: Arc<AtomicUsize>,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#[workflow_methods(factory_only)]
|
|
211
|
+
impl NondeterministicTimerWf {
|
|
212
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
213
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
214
|
+
if ctx.state(|wf| wf.started_count.fetch_add(1, Ordering::Relaxed)) == 0 {
|
|
215
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
216
|
+
}
|
|
217
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
218
|
+
Ok(())
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
151
222
|
/// Verifies nondeterministic behavior in workflows results in automatic WFT failure with the
|
|
152
223
|
/// appropriate nondeterminism cause.
|
|
153
224
|
#[rstest::rstest]
|
|
@@ -162,11 +233,9 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
162
233
|
let mut mh = MockPollCfg::from_resp_batches(
|
|
163
234
|
wf_id,
|
|
164
235
|
t,
|
|
165
|
-
// Two polls are needed, since the first will fail
|
|
166
236
|
[ResponseType::AllHistory, ResponseType::AllHistory],
|
|
167
237
|
mock,
|
|
168
238
|
);
|
|
169
|
-
// We should see one wft failure which has nondeterminism cause
|
|
170
239
|
mh.num_expected_fails = 1;
|
|
171
240
|
mh.expect_fail_wft_matcher =
|
|
172
241
|
Box::new(|_, cause, _| matches!(cause, WorkflowTaskFailedCause::NonDeterministicError));
|
|
@@ -176,32 +245,73 @@ async fn test_wf_task_rejected_properly_due_to_nondeterminism(#[case] use_cache:
|
|
|
176
245
|
}
|
|
177
246
|
});
|
|
178
247
|
|
|
179
|
-
let started_count
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if started_count.fetch_add(1, Ordering::Relaxed) == 0 {
|
|
184
|
-
ctx.timer(Duration::from_secs(1)).await;
|
|
185
|
-
}
|
|
186
|
-
ctx.timer(Duration::from_secs(1)).await;
|
|
187
|
-
Ok(().into())
|
|
248
|
+
let started_count = Arc::new(AtomicUsize::new(0));
|
|
249
|
+
let count_clone = started_count.clone();
|
|
250
|
+
worker.register_workflow_with_factory(move || NondeterministicTimerWf {
|
|
251
|
+
started_count: count_clone.clone(),
|
|
188
252
|
});
|
|
189
253
|
|
|
254
|
+
let task_queue = "fake_tq".to_owned();
|
|
190
255
|
worker
|
|
191
256
|
.submit_wf(
|
|
192
|
-
wf_id.to_owned(),
|
|
193
257
|
wf_type.to_owned(),
|
|
194
258
|
vec![],
|
|
195
|
-
|
|
259
|
+
WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
|
|
196
260
|
)
|
|
197
261
|
.await
|
|
198
262
|
.unwrap();
|
|
199
263
|
worker.run_until_done().await.unwrap();
|
|
200
|
-
// Started count is two since we start, restart once due to error, then we unblock the real
|
|
201
|
-
// timer and proceed without restarting
|
|
202
264
|
assert_eq!(2, started_count.load(Ordering::Relaxed));
|
|
203
265
|
}
|
|
204
266
|
|
|
267
|
+
#[workflow]
|
|
268
|
+
#[derive(Default)]
|
|
269
|
+
struct ActivityIdOrTypeChangeWf;
|
|
270
|
+
|
|
271
|
+
#[workflow_methods]
|
|
272
|
+
impl ActivityIdOrTypeChangeWf {
|
|
273
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
274
|
+
async fn run(
|
|
275
|
+
ctx: &mut WorkflowContext<Self>,
|
|
276
|
+
(id_change, local_act): (bool, bool),
|
|
277
|
+
) -> WorkflowResult<()> {
|
|
278
|
+
if local_act {
|
|
279
|
+
if id_change {
|
|
280
|
+
ctx.start_local_activity(
|
|
281
|
+
StdActivities::default,
|
|
282
|
+
(),
|
|
283
|
+
LocalActivityOptions {
|
|
284
|
+
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
285
|
+
..Default::default()
|
|
286
|
+
},
|
|
287
|
+
)
|
|
288
|
+
.await
|
|
289
|
+
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
290
|
+
} else {
|
|
291
|
+
ctx.start_local_activity(StdActivities::no_op, (), Default::default())
|
|
292
|
+
.await
|
|
293
|
+
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
294
|
+
}
|
|
295
|
+
} else if id_change {
|
|
296
|
+
ctx.start_activity(
|
|
297
|
+
StdActivities::default,
|
|
298
|
+
(),
|
|
299
|
+
ActivityOptions {
|
|
300
|
+
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
301
|
+
..Default::default()
|
|
302
|
+
},
|
|
303
|
+
)
|
|
304
|
+
.await
|
|
305
|
+
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
306
|
+
} else {
|
|
307
|
+
ctx.start_activity(StdActivities::no_op, (), ActivityOptions::default())
|
|
308
|
+
.await
|
|
309
|
+
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
310
|
+
}
|
|
311
|
+
Ok(())
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
205
315
|
#[rstest::rstest]
|
|
206
316
|
#[tokio::test]
|
|
207
317
|
async fn activity_id_or_type_change_is_nondeterministic(
|
|
@@ -217,15 +327,14 @@ async fn activity_id_or_type_change_is_nondeterministic(
|
|
|
217
327
|
canned_histories::single_activity("1")
|
|
218
328
|
};
|
|
219
329
|
t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
|
|
330
|
+
t.set_wf_input((id_change, local_act).as_json_payload().unwrap());
|
|
220
331
|
let mock = mock_worker_client();
|
|
221
332
|
let mut mh = MockPollCfg::from_resp_batches(
|
|
222
333
|
wf_id,
|
|
223
334
|
t,
|
|
224
|
-
// Two polls are needed, since the first will fail
|
|
225
335
|
[ResponseType::AllHistory, ResponseType::AllHistory],
|
|
226
336
|
mock,
|
|
227
337
|
);
|
|
228
|
-
// We should see one wft failure which has nondeterminism cause
|
|
229
338
|
mh.num_expected_fails = 1;
|
|
230
339
|
mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
|
|
231
340
|
let should_contain = if id_change {
|
|
@@ -244,52 +353,47 @@ async fn activity_id_or_type_change_is_nondeterministic(
|
|
|
244
353
|
cfg.max_cached_workflows = 2;
|
|
245
354
|
}
|
|
246
355
|
});
|
|
356
|
+
worker.register_workflow::<ActivityIdOrTypeChangeWf>();
|
|
247
357
|
|
|
248
|
-
|
|
249
|
-
if local_act {
|
|
250
|
-
ctx.local_activity(if id_change {
|
|
251
|
-
LocalActivityOptions {
|
|
252
|
-
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
253
|
-
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
254
|
-
..Default::default()
|
|
255
|
-
}
|
|
256
|
-
} else {
|
|
257
|
-
LocalActivityOptions {
|
|
258
|
-
activity_type: "not the default act type".to_string(),
|
|
259
|
-
..Default::default()
|
|
260
|
-
}
|
|
261
|
-
})
|
|
262
|
-
.await;
|
|
263
|
-
} else {
|
|
264
|
-
ctx.activity(if id_change {
|
|
265
|
-
ActivityOptions {
|
|
266
|
-
activity_id: Some("I'm bad and wrong!".to_string()),
|
|
267
|
-
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
268
|
-
..Default::default()
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
ActivityOptions {
|
|
272
|
-
activity_type: "not the default act type".to_string(),
|
|
273
|
-
..Default::default()
|
|
274
|
-
}
|
|
275
|
-
})
|
|
276
|
-
.await;
|
|
277
|
-
}
|
|
278
|
-
Ok(().into())
|
|
279
|
-
});
|
|
280
|
-
|
|
358
|
+
let task_queue = "fake_tq".to_owned();
|
|
281
359
|
worker
|
|
282
360
|
.submit_wf(
|
|
283
|
-
wf_id.to_owned(),
|
|
284
361
|
wf_type.to_owned(),
|
|
285
|
-
vec![],
|
|
286
|
-
|
|
362
|
+
vec![(id_change, local_act).as_json_payload().unwrap()],
|
|
363
|
+
WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
|
|
287
364
|
)
|
|
288
365
|
.await
|
|
289
366
|
.unwrap();
|
|
290
367
|
worker.run_until_done().await.unwrap();
|
|
291
368
|
}
|
|
292
369
|
|
|
370
|
+
#[workflow]
|
|
371
|
+
#[derive(Default)]
|
|
372
|
+
struct ChildWfIdOrTypeChangeWf;
|
|
373
|
+
|
|
374
|
+
#[workflow_methods]
|
|
375
|
+
impl ChildWfIdOrTypeChangeWf {
|
|
376
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
377
|
+
async fn run(ctx: &mut WorkflowContext<Self>, id_change: bool) -> WorkflowResult<()> {
|
|
378
|
+
ctx.child_workflow(if id_change {
|
|
379
|
+
ChildWorkflowOptions {
|
|
380
|
+
workflow_id: "I'm bad and wrong!".to_string(),
|
|
381
|
+
workflow_type: "child".to_string(),
|
|
382
|
+
..Default::default()
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
ChildWorkflowOptions {
|
|
386
|
+
workflow_id: "1".to_string(),
|
|
387
|
+
workflow_type: "not the child wf type".to_string(),
|
|
388
|
+
..Default::default()
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
.start()
|
|
392
|
+
.await;
|
|
393
|
+
Ok(())
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
293
397
|
#[rstest::rstest]
|
|
294
398
|
#[tokio::test]
|
|
295
399
|
async fn child_wf_id_or_type_change_is_nondeterministic(
|
|
@@ -300,15 +404,14 @@ async fn child_wf_id_or_type_change_is_nondeterministic(
|
|
|
300
404
|
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
301
405
|
let mut t = canned_histories::single_child_workflow("1");
|
|
302
406
|
t.set_flags_first_wft(&[CoreInternalFlags::IdAndTypeDeterminismChecks as u32], &[]);
|
|
407
|
+
t.set_wf_input(id_change.as_json_payload().unwrap());
|
|
303
408
|
let mock = mock_worker_client();
|
|
304
409
|
let mut mh = MockPollCfg::from_resp_batches(
|
|
305
410
|
wf_id,
|
|
306
411
|
t,
|
|
307
|
-
// Two polls are needed, since the first will fail
|
|
308
412
|
[ResponseType::AllHistory, ResponseType::AllHistory],
|
|
309
413
|
mock,
|
|
310
414
|
);
|
|
311
|
-
// We should see one wft failure which has nondeterminism cause
|
|
312
415
|
mh.num_expected_fails = 1;
|
|
313
416
|
mh.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
|
|
314
417
|
let should_contain = if id_change {
|
|
@@ -328,37 +431,34 @@ async fn child_wf_id_or_type_change_is_nondeterministic(
|
|
|
328
431
|
}
|
|
329
432
|
});
|
|
330
433
|
|
|
331
|
-
worker.
|
|
332
|
-
ctx.child_workflow(if id_change {
|
|
333
|
-
ChildWorkflowOptions {
|
|
334
|
-
workflow_id: "I'm bad and wrong!".to_string(),
|
|
335
|
-
workflow_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
336
|
-
..Default::default()
|
|
337
|
-
}
|
|
338
|
-
} else {
|
|
339
|
-
ChildWorkflowOptions {
|
|
340
|
-
workflow_id: "1".to_string(),
|
|
341
|
-
workflow_type: "not the child wf type".to_string(),
|
|
342
|
-
..Default::default()
|
|
343
|
-
}
|
|
344
|
-
})
|
|
345
|
-
.start(&ctx)
|
|
346
|
-
.await;
|
|
347
|
-
Ok(().into())
|
|
348
|
-
});
|
|
434
|
+
worker.register_workflow::<ChildWfIdOrTypeChangeWf>();
|
|
349
435
|
|
|
436
|
+
let task_queue = "fake_tq".to_owned();
|
|
350
437
|
worker
|
|
351
438
|
.submit_wf(
|
|
352
|
-
wf_id.to_owned(),
|
|
353
439
|
wf_type.to_owned(),
|
|
354
|
-
vec![],
|
|
355
|
-
|
|
440
|
+
vec![id_change.as_json_payload().unwrap()],
|
|
441
|
+
WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
|
|
356
442
|
)
|
|
357
443
|
.await
|
|
358
444
|
.unwrap();
|
|
359
445
|
worker.run_until_done().await.unwrap();
|
|
360
446
|
}
|
|
361
447
|
|
|
448
|
+
#[workflow]
|
|
449
|
+
#[derive(Default)]
|
|
450
|
+
struct ReproChannelMissingWf;
|
|
451
|
+
|
|
452
|
+
#[workflow_methods]
|
|
453
|
+
impl ReproChannelMissingWf {
|
|
454
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
455
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
456
|
+
ctx.patched("wrongid");
|
|
457
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
458
|
+
Ok(())
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
362
462
|
/// Repros a situation where if, upon completing a task there is some internal error which causes
|
|
363
463
|
/// us to want to auto-fail the workflow task while there is also an outstanding eviction, the wf
|
|
364
464
|
/// would get evicted but then try to send some info down the completion channel afterward, causing
|
|
@@ -384,18 +484,14 @@ async fn repro_channel_missing_because_nondeterminism() {
|
|
|
384
484
|
cfg.ignore_evicts_on_shutdown = false;
|
|
385
485
|
});
|
|
386
486
|
|
|
387
|
-
worker.
|
|
388
|
-
ctx.patched("wrongid");
|
|
389
|
-
ctx.timer(Duration::from_secs(1)).await;
|
|
390
|
-
Ok(().into())
|
|
391
|
-
});
|
|
487
|
+
worker.register_workflow::<ReproChannelMissingWf>();
|
|
392
488
|
|
|
489
|
+
let task_queue = "fake_tq".to_owned();
|
|
393
490
|
worker
|
|
394
491
|
.submit_wf(
|
|
395
|
-
wf_id.to_owned(),
|
|
396
492
|
wf_type.to_owned(),
|
|
397
493
|
vec![],
|
|
398
|
-
|
|
494
|
+
WorkflowStartOptions::new(task_queue, wf_id.to_owned()).build(),
|
|
399
495
|
)
|
|
400
496
|
.await
|
|
401
497
|
.unwrap();
|