@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
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
//! Tests for SDK-level query handling
|
|
2
|
+
|
|
3
|
+
use crate::common::build_fake_sdk;
|
|
4
|
+
use serde::{Deserialize, Serialize};
|
|
5
|
+
use std::{collections::HashMap, future::poll_fn, task::Poll, time::Duration};
|
|
6
|
+
use temporalio_common::protos::{
|
|
7
|
+
DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder,
|
|
8
|
+
coresdk::workflow_commands::query_result,
|
|
9
|
+
temporal::api::{
|
|
10
|
+
common::v1::WorkflowType,
|
|
11
|
+
enums::v1::{CommandType, EventType},
|
|
12
|
+
history::v1::WorkflowExecutionStartedEventAttributes,
|
|
13
|
+
query::v1::WorkflowQuery,
|
|
14
|
+
taskqueue::v1::TaskQueue,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
use temporalio_macros::{workflow, workflow_methods};
|
|
18
|
+
use temporalio_sdk::{SyncWorkflowContext, WorkflowContext, WorkflowContextView, WorkflowResult};
|
|
19
|
+
use temporalio_sdk_core::test_help::{
|
|
20
|
+
MockPollCfg, ResponseType, hist_to_poll_resp, mock_worker_client,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/// A workflow that returns Pending on first poll and Ready on second poll.
|
|
24
|
+
/// Uses workflow state to track whether it has been polled before.
|
|
25
|
+
#[workflow]
|
|
26
|
+
#[derive(Default)]
|
|
27
|
+
struct CompleteOnSecondPollWf {
|
|
28
|
+
polled_once: bool,
|
|
29
|
+
value: u32,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[workflow_methods]
|
|
33
|
+
impl CompleteOnSecondPollWf {
|
|
34
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
35
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<u32> {
|
|
36
|
+
poll_fn(|_| {
|
|
37
|
+
if ctx.state(|s| s.polled_once) {
|
|
38
|
+
Poll::Ready(())
|
|
39
|
+
} else {
|
|
40
|
+
ctx.state_mut(|s| s.polled_once = true);
|
|
41
|
+
Poll::Pending
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
.await;
|
|
45
|
+
Ok(42)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[query]
|
|
49
|
+
fn get_value(&self, _ctx: &WorkflowContextView) -> u32 {
|
|
50
|
+
self.value
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// This test demonstrates a bug where the SDK advances the workflow future even when
|
|
55
|
+
/// receiving a query-only activation. When the workflow would complete on the next poll,
|
|
56
|
+
/// this causes both a query response AND a workflow completion command to be sent
|
|
57
|
+
/// together, which is invalid.
|
|
58
|
+
///
|
|
59
|
+
/// The error message from core when this happens is:
|
|
60
|
+
/// "Workflow completion had a legacy query response along with other commands.
|
|
61
|
+
/// This is not allowed and constitutes an error in the lang SDK."
|
|
62
|
+
#[tokio::test]
|
|
63
|
+
async fn query_only_activation_should_not_advance_workflow() {
|
|
64
|
+
let mut t = TestHistoryBuilder::default();
|
|
65
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
66
|
+
t.add_full_wf_task();
|
|
67
|
+
|
|
68
|
+
let wfid = "query_only_test";
|
|
69
|
+
|
|
70
|
+
let tasks = [
|
|
71
|
+
hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
|
|
72
|
+
{
|
|
73
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1));
|
|
74
|
+
pr.query = Some(WorkflowQuery {
|
|
75
|
+
query_type: "get_value".to_string(),
|
|
76
|
+
query_args: None,
|
|
77
|
+
header: None,
|
|
78
|
+
});
|
|
79
|
+
pr.history = Some(Default::default());
|
|
80
|
+
pr
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
let mut mock_cfg = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_worker_client());
|
|
85
|
+
mock_cfg.num_expected_legacy_query_resps = 1;
|
|
86
|
+
|
|
87
|
+
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
|
|
88
|
+
asserts
|
|
89
|
+
.then(|wft| {
|
|
90
|
+
let has_complete_cmd = wft
|
|
91
|
+
.commands
|
|
92
|
+
.iter()
|
|
93
|
+
.any(|c| c.command_type() == CommandType::CompleteWorkflowExecution);
|
|
94
|
+
assert!(
|
|
95
|
+
!has_complete_cmd,
|
|
96
|
+
"First activation should not complete workflow! Commands: {:?}",
|
|
97
|
+
wft.commands
|
|
98
|
+
);
|
|
99
|
+
})
|
|
100
|
+
.then(|wft| {
|
|
101
|
+
let has_complete_cmd = wft
|
|
102
|
+
.commands
|
|
103
|
+
.iter()
|
|
104
|
+
.any(|c| c.command_type() == CommandType::CompleteWorkflowExecution);
|
|
105
|
+
assert!(
|
|
106
|
+
!has_complete_cmd,
|
|
107
|
+
"Query-only activation should NOT cause workflow completion! Commands: {:?}",
|
|
108
|
+
wft.commands
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
let mut worker = build_fake_sdk(mock_cfg);
|
|
114
|
+
worker.register_workflow::<CompleteOnSecondPollWf>();
|
|
115
|
+
worker.run().await.unwrap();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// Test that a query for a non-existent handler doesn't advance the workflow either.
|
|
119
|
+
#[tokio::test]
|
|
120
|
+
async fn nonexistent_query_should_not_advance_workflow() {
|
|
121
|
+
let mut t = TestHistoryBuilder::default();
|
|
122
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
123
|
+
t.add_full_wf_task();
|
|
124
|
+
|
|
125
|
+
let wfid = "nonexistent_query_test";
|
|
126
|
+
|
|
127
|
+
let tasks = [
|
|
128
|
+
hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1)),
|
|
129
|
+
{
|
|
130
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1));
|
|
131
|
+
pr.query = Some(WorkflowQuery {
|
|
132
|
+
query_type: "__temporal_workflow_metadata".to_string(),
|
|
133
|
+
query_args: None,
|
|
134
|
+
header: None,
|
|
135
|
+
});
|
|
136
|
+
pr.history = Some(Default::default());
|
|
137
|
+
pr
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
let mut mock_cfg = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_worker_client());
|
|
142
|
+
mock_cfg.num_expected_legacy_query_resps = 1;
|
|
143
|
+
|
|
144
|
+
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
|
|
145
|
+
asserts
|
|
146
|
+
.then(|wft| {
|
|
147
|
+
let has_complete_cmd = wft
|
|
148
|
+
.commands
|
|
149
|
+
.iter()
|
|
150
|
+
.any(|c| c.command_type() == CommandType::CompleteWorkflowExecution);
|
|
151
|
+
assert!(
|
|
152
|
+
!has_complete_cmd,
|
|
153
|
+
"First activation should not complete workflow! Commands: {:?}",
|
|
154
|
+
wft.commands
|
|
155
|
+
);
|
|
156
|
+
})
|
|
157
|
+
.then(|wft| {
|
|
158
|
+
let has_complete_cmd = wft
|
|
159
|
+
.commands
|
|
160
|
+
.iter()
|
|
161
|
+
.any(|c| c.command_type() == CommandType::CompleteWorkflowExecution);
|
|
162
|
+
assert!(
|
|
163
|
+
!has_complete_cmd,
|
|
164
|
+
"Nonexistent query should NOT cause workflow completion! Commands: {:?}",
|
|
165
|
+
wft.commands
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
let mut worker = build_fake_sdk(mock_cfg);
|
|
171
|
+
worker.register_workflow::<CompleteOnSecondPollWf>();
|
|
172
|
+
worker.run().await.unwrap();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// A workflow that increments a counter when started and when it receives a signal.
|
|
176
|
+
/// Used to test that non-legacy queries see state after the workflow has advanced.
|
|
177
|
+
#[workflow]
|
|
178
|
+
#[derive(Default)]
|
|
179
|
+
struct CounterWf {
|
|
180
|
+
counter: u32,
|
|
181
|
+
got_signal: bool,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#[workflow_methods]
|
|
185
|
+
impl CounterWf {
|
|
186
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
187
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
188
|
+
ctx.state_mut(|s| s.counter += 1);
|
|
189
|
+
ctx.wait_condition(|s| s.got_signal).await;
|
|
190
|
+
ctx.state_mut(|s| s.counter += 1);
|
|
191
|
+
Ok(())
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#[signal]
|
|
195
|
+
fn my_signal(&mut self, _ctx: &mut SyncWorkflowContext<Self>) {
|
|
196
|
+
self.got_signal = true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#[query]
|
|
200
|
+
fn get_counter(&self, _ctx: &WorkflowContextView) -> u32 {
|
|
201
|
+
self.counter
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/// Non-legacy queries (in the `queries` field) come bundled with new history.
|
|
206
|
+
/// Core sends these queries in their own activation after the workflow has processed
|
|
207
|
+
/// the history, so queries should observe state AFTER the workflow has advanced.
|
|
208
|
+
#[tokio::test]
|
|
209
|
+
async fn non_legacy_query_should_see_state_after_workflow_advances() {
|
|
210
|
+
let wfid = "non_legacy_query_state_test";
|
|
211
|
+
|
|
212
|
+
let mut t = TestHistoryBuilder::default();
|
|
213
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
214
|
+
t.add_full_wf_task();
|
|
215
|
+
t.add_we_signaled("my_signal", vec![]);
|
|
216
|
+
t.add_full_wf_task();
|
|
217
|
+
t.add_workflow_execution_completed();
|
|
218
|
+
|
|
219
|
+
let tasks = [
|
|
220
|
+
{
|
|
221
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(1));
|
|
222
|
+
pr.queries = HashMap::from([(
|
|
223
|
+
"q1".to_string(),
|
|
224
|
+
WorkflowQuery {
|
|
225
|
+
query_type: "get_counter".to_string(),
|
|
226
|
+
query_args: None,
|
|
227
|
+
header: None,
|
|
228
|
+
},
|
|
229
|
+
)]);
|
|
230
|
+
pr
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::ToTaskNum(2));
|
|
234
|
+
pr.queries = HashMap::from([(
|
|
235
|
+
"q2".to_string(),
|
|
236
|
+
WorkflowQuery {
|
|
237
|
+
query_type: "get_counter".to_string(),
|
|
238
|
+
query_args: None,
|
|
239
|
+
header: None,
|
|
240
|
+
},
|
|
241
|
+
)]);
|
|
242
|
+
pr
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
let mut mock_cfg = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_worker_client());
|
|
247
|
+
|
|
248
|
+
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
|
|
249
|
+
asserts
|
|
250
|
+
.then(|wft| {
|
|
251
|
+
assert_eq!(wft.query_responses.len(), 1);
|
|
252
|
+
let query_resp = &wft.query_responses[0];
|
|
253
|
+
assert_eq!(query_resp.query_id, "q1");
|
|
254
|
+
|
|
255
|
+
match &query_resp.variant {
|
|
256
|
+
Some(query_result::Variant::Succeeded(success)) => {
|
|
257
|
+
let payload = success
|
|
258
|
+
.response
|
|
259
|
+
.as_ref()
|
|
260
|
+
.expect("Expected response payload");
|
|
261
|
+
let value: u32 =
|
|
262
|
+
serde_json::from_slice(&payload.data).expect("Expected u32 payload");
|
|
263
|
+
assert_eq!(
|
|
264
|
+
value, 1,
|
|
265
|
+
"After start, counter should be 1 but got {}",
|
|
266
|
+
value
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
other => panic!("Expected successful query response, got {:?}", other),
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
.then(|wft| {
|
|
273
|
+
assert_eq!(wft.query_responses.len(), 1);
|
|
274
|
+
let query_resp = &wft.query_responses[0];
|
|
275
|
+
assert_eq!(query_resp.query_id, "q2");
|
|
276
|
+
|
|
277
|
+
match &query_resp.variant {
|
|
278
|
+
Some(query_result::Variant::Succeeded(success)) => {
|
|
279
|
+
let payload = success
|
|
280
|
+
.response
|
|
281
|
+
.as_ref()
|
|
282
|
+
.expect("Expected response payload");
|
|
283
|
+
let value: u32 =
|
|
284
|
+
serde_json::from_slice(&payload.data).expect("Expected u32 payload");
|
|
285
|
+
assert_eq!(
|
|
286
|
+
value, 2,
|
|
287
|
+
"After signal, counter should be 2 but got {}",
|
|
288
|
+
value
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
other => panic!("Expected successful query response, got {:?}", other),
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
let mut worker = build_fake_sdk(mock_cfg);
|
|
297
|
+
worker.register_workflow::<CounterWf>();
|
|
298
|
+
worker.run().await.unwrap();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// Struct to capture WorkflowContextView information for testing.
|
|
302
|
+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
303
|
+
struct WorkflowInfo {
|
|
304
|
+
workflow_id: String,
|
|
305
|
+
workflow_type: String,
|
|
306
|
+
task_queue: String,
|
|
307
|
+
namespace: String,
|
|
308
|
+
attempt: u32,
|
|
309
|
+
first_execution_run_id: String,
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
impl<'a> From<&'a WorkflowContextView> for WorkflowInfo {
|
|
313
|
+
fn from(ctx: &'a WorkflowContextView) -> Self {
|
|
314
|
+
Self {
|
|
315
|
+
workflow_id: ctx.workflow_id.clone(),
|
|
316
|
+
workflow_type: ctx.workflow_type.clone(),
|
|
317
|
+
task_queue: ctx.task_queue.clone(),
|
|
318
|
+
namespace: ctx.namespace.clone(),
|
|
319
|
+
attempt: ctx.attempt,
|
|
320
|
+
first_execution_run_id: ctx.first_execution_run_id.clone(),
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/// A workflow that captures context view information at initialization time.
|
|
326
|
+
#[workflow]
|
|
327
|
+
struct ContextViewWf;
|
|
328
|
+
|
|
329
|
+
#[workflow_methods]
|
|
330
|
+
impl ContextViewWf {
|
|
331
|
+
#[init]
|
|
332
|
+
fn new(_ctx: &WorkflowContextView) -> Self {
|
|
333
|
+
Self
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
#[run(name = "context_view_wf")]
|
|
337
|
+
async fn run(_ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
338
|
+
Ok(())
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
#[query]
|
|
342
|
+
fn get_info(&self, ctx: &WorkflowContextView) -> WorkflowInfo {
|
|
343
|
+
ctx.into()
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/// Test that WorkflowContextView contains the correct workflow information.
|
|
348
|
+
#[tokio::test]
|
|
349
|
+
async fn query_returns_workflow_context_view_info() {
|
|
350
|
+
const WFID: &str = "context_view_test_wf";
|
|
351
|
+
const FIRST_RUN_ID: &str = "first-run-id-12345";
|
|
352
|
+
|
|
353
|
+
let mut t = TestHistoryBuilder::default();
|
|
354
|
+
t.add(WorkflowExecutionStartedEventAttributes {
|
|
355
|
+
workflow_type: Some(WorkflowType {
|
|
356
|
+
name: "context_view_wf".to_string(),
|
|
357
|
+
}),
|
|
358
|
+
task_queue: Some(TaskQueue {
|
|
359
|
+
name: "test-task-queue".to_string(),
|
|
360
|
+
..Default::default()
|
|
361
|
+
}),
|
|
362
|
+
first_execution_run_id: FIRST_RUN_ID.to_string(),
|
|
363
|
+
attempt: 3,
|
|
364
|
+
workflow_task_timeout: Some(Duration::from_secs(5).try_into().unwrap()),
|
|
365
|
+
..Default::default()
|
|
366
|
+
});
|
|
367
|
+
t.add_full_wf_task();
|
|
368
|
+
t.add_workflow_execution_completed();
|
|
369
|
+
|
|
370
|
+
let tasks = [{
|
|
371
|
+
let mut pr = hist_to_poll_resp(&t, WFID.to_owned(), ResponseType::ToTaskNum(1));
|
|
372
|
+
pr.queries = HashMap::from([(
|
|
373
|
+
"q1".to_string(),
|
|
374
|
+
WorkflowQuery {
|
|
375
|
+
query_type: "get_info".to_string(),
|
|
376
|
+
query_args: None,
|
|
377
|
+
header: None,
|
|
378
|
+
},
|
|
379
|
+
)]);
|
|
380
|
+
pr
|
|
381
|
+
}];
|
|
382
|
+
|
|
383
|
+
let mut mock_cfg = MockPollCfg::from_resp_batches(WFID, t, tasks, mock_worker_client());
|
|
384
|
+
|
|
385
|
+
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
|
|
386
|
+
asserts.then(|wft| {
|
|
387
|
+
assert_eq!(wft.query_responses.len(), 1);
|
|
388
|
+
let query_resp = &wft.query_responses[0];
|
|
389
|
+
assert_eq!(query_resp.query_id, "q1");
|
|
390
|
+
|
|
391
|
+
match &query_resp.variant {
|
|
392
|
+
Some(query_result::Variant::Succeeded(success)) => {
|
|
393
|
+
let payload = success
|
|
394
|
+
.response
|
|
395
|
+
.as_ref()
|
|
396
|
+
.expect("Expected response payload");
|
|
397
|
+
let info: WorkflowInfo =
|
|
398
|
+
serde_json::from_slice(&payload.data).expect("Expected WorkflowInfo");
|
|
399
|
+
|
|
400
|
+
assert_eq!(info.workflow_id, WFID);
|
|
401
|
+
assert_eq!(info.workflow_type, "context_view_wf");
|
|
402
|
+
// task_queue comes from worker config, not workflow history
|
|
403
|
+
assert_eq!(info.namespace, "default");
|
|
404
|
+
assert_eq!(info.attempt, 3);
|
|
405
|
+
assert_eq!(info.first_execution_run_id, FIRST_RUN_ID);
|
|
406
|
+
}
|
|
407
|
+
other => panic!("Expected successful query response, got {:?}", other),
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
let mut worker = build_fake_sdk(mock_cfg);
|
|
413
|
+
worker.register_workflow::<ContextViewWf>();
|
|
414
|
+
worker.run().await.unwrap();
|
|
415
|
+
}
|
|
@@ -3,17 +3,17 @@ use crate::{
|
|
|
3
3
|
ActivationAssertionsInterceptor, build_fake_sdk, history_from_proto_binary,
|
|
4
4
|
init_core_replay_preloaded, replay_sdk_worker, replay_sdk_worker_stream,
|
|
5
5
|
},
|
|
6
|
-
integ_tests::workflow_tests::patches::
|
|
6
|
+
integ_tests::workflow_tests::patches::ChangesWf,
|
|
7
7
|
};
|
|
8
8
|
use assert_matches::assert_matches;
|
|
9
9
|
use parking_lot::Mutex;
|
|
10
10
|
use std::{collections::HashSet, sync::Arc, time::Duration};
|
|
11
11
|
use temporalio_common::{
|
|
12
|
-
errors::PollError,
|
|
13
12
|
prost_dur,
|
|
14
13
|
protos::{
|
|
15
14
|
DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, canned_histories,
|
|
16
15
|
coresdk::{
|
|
16
|
+
AsJsonPayloadExt,
|
|
17
17
|
workflow_activation::remove_from_cache::EvictionReason,
|
|
18
18
|
workflow_commands::{ScheduleActivity, StartTimer},
|
|
19
19
|
workflow_completion::WorkflowActivationCompletion,
|
|
@@ -21,34 +21,50 @@ use temporalio_common::{
|
|
|
21
21
|
temporal::api::enums::v1::EventType,
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
|
-
use
|
|
24
|
+
use temporalio_macros::{workflow, workflow_methods};
|
|
25
|
+
use temporalio_sdk::{
|
|
26
|
+
Worker, WorkflowContext, WorkflowContextView, WorkflowResult, interceptors::WorkerInterceptor,
|
|
27
|
+
};
|
|
25
28
|
use temporalio_sdk_core::{
|
|
29
|
+
PollError,
|
|
26
30
|
replay::{HistoryFeeder, HistoryForReplay},
|
|
27
31
|
test_help::{MockPollCfg, ResponseType, WorkerTestHelpers},
|
|
28
32
|
};
|
|
29
33
|
use tokio::join;
|
|
30
34
|
|
|
31
35
|
fn test_hist_to_replay(t: TestHistoryBuilder) -> HistoryForReplay {
|
|
32
|
-
let hi = t.get_full_history_info().unwrap()
|
|
36
|
+
let hi = t.get_full_history_info().unwrap();
|
|
33
37
|
HistoryForReplay::new(hi, "fake".to_string())
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
#[workflow]
|
|
41
|
+
struct TimersWf {
|
|
42
|
+
num_timers: u32,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[workflow_methods]
|
|
46
|
+
impl TimersWf {
|
|
47
|
+
#[init]
|
|
48
|
+
fn new(_ctx: &WorkflowContextView, num_timers: u32) -> Self {
|
|
49
|
+
Self { num_timers }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[run(name = DEFAULT_WORKFLOW_TYPE)]
|
|
53
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
54
|
+
let num_timers = ctx.state(|wf| wf.num_timers);
|
|
38
55
|
for _ in 1..=num_timers {
|
|
39
56
|
ctx.timer(Duration::from_secs(1)).await;
|
|
40
57
|
}
|
|
41
|
-
Ok(()
|
|
42
|
-
}
|
|
58
|
+
Ok(())
|
|
59
|
+
}
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
#[fixture(num_timers = 1)]
|
|
46
63
|
fn fire_happy_hist(num_timers: u32) -> Worker {
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
let t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
64
|
+
let mut t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
65
|
+
t.set_wf_input(num_timers.as_json_payload().unwrap());
|
|
50
66
|
let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [ResponseType::AllHistory]));
|
|
51
|
-
worker.
|
|
67
|
+
worker.register_workflow::<TimersWf>();
|
|
52
68
|
worker
|
|
53
69
|
}
|
|
54
70
|
|
|
@@ -72,11 +88,10 @@ async fn replay_flag_is_correct(#[case] mut worker: Worker, #[case] num_timers:
|
|
|
72
88
|
|
|
73
89
|
#[tokio::test(flavor = "multi_thread")]
|
|
74
90
|
async fn replay_flag_is_correct_partial_history() {
|
|
75
|
-
let
|
|
76
|
-
|
|
77
|
-
let t = canned_histories::long_sequential_timers(2);
|
|
91
|
+
let mut t = canned_histories::long_sequential_timers(2);
|
|
92
|
+
t.set_wf_input(1u32.as_json_payload().unwrap());
|
|
78
93
|
let mut worker = build_fake_sdk(MockPollCfg::from_resps(t, [1]));
|
|
79
|
-
worker.
|
|
94
|
+
worker.register_workflow::<TimersWf>();
|
|
80
95
|
|
|
81
96
|
let mut aai = ActivationAssertionsInterceptor::default();
|
|
82
97
|
aai.then(|a| assert!(!a.is_replaying));
|
|
@@ -184,11 +199,11 @@ async fn workflow_nondeterministic_replay() {
|
|
|
184
199
|
|
|
185
200
|
#[tokio::test]
|
|
186
201
|
async fn replay_using_wf_function() {
|
|
187
|
-
let num_timers =
|
|
188
|
-
let t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
189
|
-
|
|
202
|
+
let num_timers = 10u32;
|
|
203
|
+
let mut t = canned_histories::long_sequential_timers(num_timers as usize);
|
|
204
|
+
t.set_wf_input(num_timers.as_json_payload().unwrap());
|
|
190
205
|
let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
|
|
191
|
-
worker.
|
|
206
|
+
worker.register_workflow::<TimersWf>();
|
|
192
207
|
worker.run().await.unwrap();
|
|
193
208
|
}
|
|
194
209
|
|
|
@@ -203,16 +218,16 @@ async fn replay_ending_wft_complete_with_commands_but_no_scheduled_started() {
|
|
|
203
218
|
t.add_timer_fired(timer_started_event_id, i.to_string());
|
|
204
219
|
t.add_full_wf_task();
|
|
205
220
|
}
|
|
206
|
-
|
|
221
|
+
t.set_wf_input(3u32.as_json_payload().unwrap());
|
|
207
222
|
let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
|
|
208
|
-
worker.
|
|
223
|
+
worker.register_workflow::<TimersWf>();
|
|
209
224
|
worker.run().await.unwrap();
|
|
210
225
|
}
|
|
211
226
|
|
|
212
|
-
async fn replay_abrupt_ending(t: TestHistoryBuilder) {
|
|
213
|
-
|
|
227
|
+
async fn replay_abrupt_ending(mut t: TestHistoryBuilder) {
|
|
228
|
+
t.set_wf_input(1u32.as_json_payload().unwrap());
|
|
214
229
|
let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
|
|
215
|
-
worker.
|
|
230
|
+
worker.register_workflow::<TimersWf>();
|
|
216
231
|
worker.run().await.unwrap();
|
|
217
232
|
}
|
|
218
233
|
#[tokio::test]
|
|
@@ -230,10 +245,10 @@ async fn replay_ok_ending_with_timed_out() {
|
|
|
230
245
|
|
|
231
246
|
#[tokio::test]
|
|
232
247
|
async fn replay_shutdown_worker() {
|
|
233
|
-
let t = canned_histories::single_timer("1");
|
|
234
|
-
|
|
248
|
+
let mut t = canned_histories::single_timer("1");
|
|
249
|
+
t.set_wf_input(1u32.as_json_payload().unwrap());
|
|
235
250
|
let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
|
|
236
|
-
worker.
|
|
251
|
+
worker.register_workflow::<TimersWf>();
|
|
237
252
|
let shutdown_ctr_i = UniqueShutdownWorker::default();
|
|
238
253
|
let shutdown_ctr = shutdown_ctr_i.runs.clone();
|
|
239
254
|
worker.set_worker_interceptor(shutdown_ctr_i);
|
|
@@ -241,16 +256,60 @@ async fn replay_shutdown_worker() {
|
|
|
241
256
|
assert_eq!(shutdown_ctr.lock().len(), 1);
|
|
242
257
|
}
|
|
243
258
|
|
|
259
|
+
#[workflow]
|
|
260
|
+
struct OneTimerWf {
|
|
261
|
+
num_timers: u32,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#[workflow_methods]
|
|
265
|
+
impl OneTimerWf {
|
|
266
|
+
#[init]
|
|
267
|
+
fn new(_ctx: &WorkflowContextView, num_timers: u32) -> Self {
|
|
268
|
+
Self { num_timers }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#[run(name = "onetimer")]
|
|
272
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
273
|
+
let num_timers = ctx.state(|wf| wf.num_timers);
|
|
274
|
+
for _ in 1..=num_timers {
|
|
275
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
276
|
+
}
|
|
277
|
+
Ok(())
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
#[workflow]
|
|
282
|
+
struct SeqTimerWf {
|
|
283
|
+
num_timers: u32,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
#[workflow_methods]
|
|
287
|
+
impl SeqTimerWf {
|
|
288
|
+
#[init]
|
|
289
|
+
fn new(_ctx: &WorkflowContextView, num_timers: u32) -> Self {
|
|
290
|
+
Self { num_timers }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
#[run(name = "seqtimer")]
|
|
294
|
+
async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
|
|
295
|
+
let num_timers = ctx.state(|wf| wf.num_timers);
|
|
296
|
+
for _ in 1..=num_timers {
|
|
297
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
298
|
+
}
|
|
299
|
+
Ok(())
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
244
303
|
#[rstest::rstest]
|
|
245
304
|
#[tokio::test]
|
|
246
305
|
async fn multiple_histories_replay(#[values(false, true)] use_feeder: bool) {
|
|
247
|
-
let num_timers =
|
|
248
|
-
let seq_timer_wf = timers_wf(num_timers);
|
|
249
|
-
let one_timer_wf = timers_wf(1);
|
|
306
|
+
let num_timers = 10u32;
|
|
250
307
|
let mut one_timer_hist = canned_histories::single_timer("1");
|
|
251
308
|
one_timer_hist.set_wf_type("onetimer");
|
|
309
|
+
one_timer_hist.set_wf_input(1u32.as_json_payload().unwrap());
|
|
252
310
|
let mut seq_timer_hist = canned_histories::long_sequential_timers(num_timers as usize);
|
|
253
311
|
seq_timer_hist.set_wf_type("seqtimer");
|
|
312
|
+
seq_timer_hist.set_wf_input(num_timers.as_json_payload().unwrap());
|
|
254
313
|
let (feeder, stream) = HistoryFeeder::new(1);
|
|
255
314
|
let mut worker = if use_feeder {
|
|
256
315
|
replay_sdk_worker_stream(stream)
|
|
@@ -263,8 +322,8 @@ async fn multiple_histories_replay(#[values(false, true)] use_feeder: bool) {
|
|
|
263
322
|
let runs_ctr_i = UniqueRunsCounter::default();
|
|
264
323
|
let runs_ctr = runs_ctr_i.runs.clone();
|
|
265
324
|
worker.set_worker_interceptor(runs_ctr_i);
|
|
266
|
-
worker.
|
|
267
|
-
worker.
|
|
325
|
+
worker.register_workflow::<OneTimerWf>();
|
|
326
|
+
worker.register_workflow::<SeqTimerWf>();
|
|
268
327
|
|
|
269
328
|
if use_feeder {
|
|
270
329
|
let feed_fut = async move {
|
|
@@ -289,16 +348,17 @@ async fn multiple_histories_replay(#[values(false, true)] use_feeder: bool) {
|
|
|
289
348
|
async fn multiple_histories_can_handle_dupe_run_ids() {
|
|
290
349
|
let mut hist1 = canned_histories::single_timer("1");
|
|
291
350
|
hist1.set_wf_type("onetimer");
|
|
351
|
+
hist1.set_wf_input(1u32.as_json_payload().unwrap());
|
|
292
352
|
let mut worker = replay_sdk_worker([
|
|
293
353
|
test_hist_to_replay(hist1.clone()),
|
|
294
354
|
test_hist_to_replay(hist1.clone()),
|
|
295
355
|
test_hist_to_replay(hist1),
|
|
296
356
|
]);
|
|
297
|
-
worker.
|
|
357
|
+
worker.register_workflow::<OneTimerWf>();
|
|
298
358
|
worker.run().await.unwrap();
|
|
299
359
|
}
|
|
300
360
|
|
|
301
|
-
// Verifies SDK can decode patch markers before changing them to use json encoding
|
|
361
|
+
// Verifies SDK can decode patch markers before changing them to use json encoding.
|
|
302
362
|
#[tokio::test]
|
|
303
363
|
async fn replay_old_patch_format() {
|
|
304
364
|
let mut worker = replay_sdk_worker([HistoryForReplay::new(
|
|
@@ -307,7 +367,7 @@ async fn replay_old_patch_format() {
|
|
|
307
367
|
.unwrap(),
|
|
308
368
|
"fake".to_owned(),
|
|
309
369
|
)]);
|
|
310
|
-
worker.
|
|
370
|
+
worker.register_workflow::<ChangesWf>();
|
|
311
371
|
worker.run().await.unwrap();
|
|
312
372
|
}
|
|
313
373
|
|