@temporalio/core-bridge 1.8.6 → 1.9.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 +670 -594
- package/Cargo.toml +2 -1
- package/lib/errors.js +6 -6
- package/lib/errors.js.map +1 -1
- package/lib/index.d.ts +17 -44
- package/lib/index.js.map +1 -1
- package/package.json +5 -6
- 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/heavy.yml +4 -0
- package/sdk-core/.github/workflows/per-pr.yml +96 -0
- package/sdk-core/ARCHITECTURE.md +1 -1
- package/sdk-core/Cargo.toml +10 -0
- package/sdk-core/LICENSE.txt +0 -2
- package/sdk-core/README.md +37 -21
- package/sdk-core/client/Cargo.toml +7 -4
- package/sdk-core/client/src/lib.rs +274 -142
- package/sdk-core/client/src/metrics.rs +68 -57
- package/sdk-core/client/src/raw.rs +191 -45
- package/sdk-core/client/src/retry.rs +20 -0
- package/sdk-core/client/src/worker_registry/mod.rs +264 -0
- package/sdk-core/client/src/workflow_handle/mod.rs +2 -1
- package/sdk-core/core/Cargo.toml +17 -19
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -7
- package/sdk-core/core/src/core_tests/mod.rs +1 -0
- package/sdk-core/core/src/core_tests/queries.rs +42 -1
- package/sdk-core/core/src/core_tests/replay_flag.rs +29 -39
- package/sdk-core/core/src/core_tests/updates.rs +73 -0
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +52 -1
- package/sdk-core/core/src/ephemeral_server/mod.rs +34 -11
- package/sdk-core/core/src/internal_flags.rs +7 -1
- package/sdk-core/core/src/lib.rs +19 -36
- package/sdk-core/core/src/protosext/mod.rs +12 -4
- package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
- package/sdk-core/core/src/replay/mod.rs +99 -48
- package/sdk-core/core/src/telemetry/log_export.rs +161 -28
- package/sdk-core/core/src/telemetry/metrics.rs +869 -248
- package/sdk-core/core/src/telemetry/mod.rs +153 -257
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
- package/sdk-core/core/src/test_help/mod.rs +64 -5
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +12 -2
- package/sdk-core/core/src/worker/activities.rs +276 -10
- package/sdk-core/core/src/worker/client/mocks.rs +18 -0
- package/sdk-core/core/src/worker/client.rs +16 -3
- package/sdk-core/core/src/worker/mod.rs +45 -28
- package/sdk-core/core/src/worker/slot_provider.rs +175 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +27 -34
- package/sdk-core/core/src/worker/workflow/history_update.rs +5 -2
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +71 -95
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +34 -22
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +50 -34
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +106 -92
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +22 -21
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +386 -499
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -2
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +33 -26
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +198 -215
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +67 -63
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +88 -119
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +3 -1
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +411 -0
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +27 -26
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +319 -94
- package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
- package/sdk-core/core/src/worker/workflow/mod.rs +129 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +16 -26
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +48 -43
- package/sdk-core/core-api/Cargo.toml +8 -7
- package/sdk-core/core-api/src/lib.rs +4 -12
- package/sdk-core/core-api/src/telemetry/metrics.rs +334 -0
- package/sdk-core/core-api/src/telemetry.rs +53 -42
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/{.buildkite/docker → docker}/docker-compose.yaml +1 -1
- package/sdk-core/etc/dynamic-config.yaml +11 -1
- package/sdk-core/fsm/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +1 -3
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +2 -2
- package/sdk-core/fsm/rustfsm_trait/LICENSE.txt +0 -2
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +85 -7
- package/sdk-core/sdk/src/workflow_context/options.rs +4 -0
- package/sdk-core/sdk/src/workflow_context.rs +43 -15
- package/sdk-core/sdk/src/workflow_future.rs +334 -204
- package/sdk-core/sdk-core-protos/Cargo.toml +3 -3
- package/sdk-core/sdk-core-protos/build.rs +14 -14
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +99 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +56 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.gen.yaml +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +18 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/annotations.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/http.proto +379 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/any.proto +162 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/descriptor.proto +1212 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/duration.proto +115 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/empty.proto +51 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/timestamp.proto +144 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/wrappers.proto +123 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/batch/v1/message.proto +12 -9
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/command/v1/message.proto +11 -13
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/common/v1/message.proto +33 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
- package/sdk-core/{protos/api_upstream/build/tools.go → sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto} +22 -6
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/filter/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/history/v1/message.proto +21 -23
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/namespace/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/replication/v1/message.proto +1 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/schedule/v1/message.proto +36 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +13 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/update/v1/message.proto +1 -1
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/version/v1/message.proto +2 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflow/v1/message.proto +24 -22
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/request_response.proto +84 -32
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/service.proto +205 -47
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +57 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +27 -0
- package/sdk-core/sdk-core-protos/src/history_builder.rs +67 -2
- package/sdk-core/sdk-core-protos/src/history_info.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +76 -3
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +6 -1
- package/sdk-core/test-utils/src/canned_histories.rs +3 -57
- package/sdk-core/test-utils/src/interceptors.rs +46 -0
- package/sdk-core/test-utils/src/lib.rs +106 -38
- package/sdk-core/tests/integ_tests/metrics_tests.rs +110 -15
- package/sdk-core/tests/integ_tests/queries_tests.rs +174 -3
- package/sdk-core/tests/integ_tests/update_tests.rs +908 -0
- package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +44 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +61 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +27 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +142 -3
- package/sdk-core/tests/main.rs +2 -1
- package/sdk-core/tests/runner.rs +15 -2
- package/src/conversions.rs +107 -96
- package/src/helpers.rs +74 -0
- package/src/runtime.rs +29 -15
- package/src/worker.rs +14 -61
- package/ts/index.ts +23 -54
- package/sdk-core/.buildkite/docker/Dockerfile +0 -9
- package/sdk-core/.buildkite/docker/build.sh +0 -5
- package/sdk-core/.buildkite/docker/docker-compose-ci.yaml +0 -27
- package/sdk-core/.buildkite/pipeline.yml +0 -57
- package/sdk-core/.github/workflows/semgrep.yml +0 -25
- package/sdk-core/client/LICENSE.txt +0 -23
- package/sdk-core/core/LICENSE.txt +0 -23
- package/sdk-core/core/src/worker/workflow/bridge.rs +0 -35
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +0 -215
- package/sdk-core/core-api/LICENSE.txt +0 -23
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/protos/api_upstream/Makefile +0 -80
- package/sdk-core/protos/api_upstream/api-linter.yaml +0 -40
- package/sdk-core/protos/api_upstream/buf.yaml +0 -9
- package/sdk-core/protos/api_upstream/build/go.mod +0 -7
- package/sdk-core/protos/api_upstream/build/go.sum +0 -5
- package/sdk-core/protos/api_upstream/go.mod +0 -6
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
- package/sdk-core/sdk/LICENSE.txt +0 -23
- package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
- /package/sdk-core/{.buildkite/docker → docker}/docker-compose-telem.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/docker-compose.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/pipeline.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/CODEOWNERS +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/publish-docs.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/LICENSE +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/README.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/query.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/update.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/failure/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/query/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/google/rpc/status.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/grpc/health/v1/health.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/common/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/core_interface.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/external_data/external_data.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/Makefile +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/api-linter.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/buf.yaml +0 -0
- /package/sdk-core/{protos/api_upstream → sdk-core-protos/protos/testsrv_upstream}/dependencies/gogoproto/gogo.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
extern crate tracing;
|
|
6
6
|
|
|
7
7
|
pub mod canned_histories;
|
|
8
|
+
pub mod interceptors;
|
|
8
9
|
pub mod wf_input_saver;
|
|
9
10
|
pub mod workflows;
|
|
10
11
|
|
|
12
|
+
use anyhow::Context;
|
|
13
|
+
pub use temporal_sdk_core::replay::HistoryForReplay;
|
|
14
|
+
|
|
11
15
|
use crate::{
|
|
12
16
|
stream::{Stream, TryStreamExt},
|
|
13
17
|
wf_input_saver::stream_to_file,
|
|
@@ -29,17 +33,19 @@ use temporal_sdk::{
|
|
|
29
33
|
interceptors::{FailOnNondeterminismInterceptor, WorkerInterceptor},
|
|
30
34
|
IntoActivityFunc, Worker, WorkflowFunction,
|
|
31
35
|
};
|
|
36
|
+
#[cfg(feature = "ephemeral-server")]
|
|
37
|
+
use temporal_sdk_core::ephemeral_server::{EphemeralExe, EphemeralExeVersion};
|
|
32
38
|
use temporal_sdk_core::{
|
|
33
|
-
ephemeral_server::{EphemeralExe, EphemeralExeVersion},
|
|
34
39
|
init_replay_worker, init_worker,
|
|
35
|
-
replay::
|
|
40
|
+
replay::ReplayWorkerInput,
|
|
41
|
+
telemetry::{build_otlp_metric_exporter, start_prometheus_metric_exporter},
|
|
36
42
|
ClientOptions, ClientOptionsBuilder, CoreRuntime, WorkerConfigBuilder,
|
|
37
43
|
};
|
|
38
44
|
use temporal_sdk_core_api::{
|
|
39
45
|
errors::{PollActivityError, PollWfError},
|
|
40
46
|
telemetry::{
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
metrics::CoreMeter, Logger, OtelCollectorOptionsBuilder, PrometheusExporterOptionsBuilder,
|
|
48
|
+
TelemetryOptions, TelemetryOptionsBuilder,
|
|
43
49
|
},
|
|
44
50
|
Worker as CoreWorker,
|
|
45
51
|
};
|
|
@@ -51,7 +57,10 @@ use temporal_sdk_core_protos::{
|
|
|
51
57
|
},
|
|
52
58
|
workflow_completion::WorkflowActivationCompletion,
|
|
53
59
|
},
|
|
54
|
-
temporal::api::{
|
|
60
|
+
temporal::api::{
|
|
61
|
+
common::v1::Payload, history::v1::History,
|
|
62
|
+
workflowservice::v1::StartWorkflowExecutionResponse,
|
|
63
|
+
},
|
|
55
64
|
DEFAULT_ACTIVITY_TYPE,
|
|
56
65
|
};
|
|
57
66
|
use tokio::sync::{mpsc::unbounded_channel, OnceCell};
|
|
@@ -82,7 +91,7 @@ macro_rules! prost_dur {
|
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
/// Create a worker instance which will use the provided test name to base the task queue and wf id
|
|
85
|
-
/// upon. Returns the instance
|
|
94
|
+
/// upon. Returns the instance.
|
|
86
95
|
pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
|
|
87
96
|
let mut starter = CoreWfStarter::new(test_name);
|
|
88
97
|
let _ = starter.get_worker().await;
|
|
@@ -109,8 +118,8 @@ where
|
|
|
109
118
|
.worker_build_id("test_bin_id")
|
|
110
119
|
.build()
|
|
111
120
|
.expect("Configuration options construct properly");
|
|
112
|
-
let worker =
|
|
113
|
-
|
|
121
|
+
let worker = init_replay_worker(ReplayWorkerInput::new(worker_cfg, histories))
|
|
122
|
+
.expect("Replay worker must init properly");
|
|
114
123
|
Arc::new(worker)
|
|
115
124
|
}
|
|
116
125
|
pub fn replay_sdk_worker<I>(histories: I) -> Worker
|
|
@@ -126,7 +135,7 @@ where
|
|
|
126
135
|
{
|
|
127
136
|
let core = init_core_replay_stream("replay_worker_test", histories);
|
|
128
137
|
let mut worker = Worker::new_from_core(core, "replay_q".to_string());
|
|
129
|
-
worker.set_worker_interceptor(
|
|
138
|
+
worker.set_worker_interceptor(FailOnNondeterminismInterceptor {});
|
|
130
139
|
worker
|
|
131
140
|
}
|
|
132
141
|
|
|
@@ -145,7 +154,9 @@ pub fn init_integ_telem() {
|
|
|
145
154
|
let telemetry_options = get_integ_telem_options();
|
|
146
155
|
let rt =
|
|
147
156
|
CoreRuntime::new_assume_tokio(telemetry_options).expect("Core runtime inits cleanly");
|
|
148
|
-
let
|
|
157
|
+
if let Some(sub) = rt.telemetry().trace_subscriber() {
|
|
158
|
+
let _ = tracing::subscriber::set_global_default(sub);
|
|
159
|
+
}
|
|
149
160
|
rt
|
|
150
161
|
});
|
|
151
162
|
}
|
|
@@ -194,6 +205,18 @@ impl CoreWfStarter {
|
|
|
194
205
|
}
|
|
195
206
|
}
|
|
196
207
|
|
|
208
|
+
/// Create a new starter with no initialized worker or runtime override. Useful for starting a
|
|
209
|
+
/// new worker on the same queue.
|
|
210
|
+
pub fn clone_no_worker(&self) -> Self {
|
|
211
|
+
Self {
|
|
212
|
+
task_queue_name: self.task_queue_name.clone(),
|
|
213
|
+
worker_config: self.worker_config.clone(),
|
|
214
|
+
workflow_options: self.workflow_options.clone(),
|
|
215
|
+
runtime_override: None,
|
|
216
|
+
initted_worker: Default::default(),
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
197
220
|
pub async fn worker(&mut self) -> TestWorker {
|
|
198
221
|
let w = self.get_worker().await;
|
|
199
222
|
let tq = w.get_config().task_queue.clone();
|
|
@@ -236,6 +259,23 @@ impl CoreWfStarter {
|
|
|
236
259
|
.unwrap()
|
|
237
260
|
}
|
|
238
261
|
|
|
262
|
+
pub async fn eager_start_with_worker(
|
|
263
|
+
&self,
|
|
264
|
+
wf_name: impl Into<String>,
|
|
265
|
+
worker: &mut TestWorker,
|
|
266
|
+
) -> StartWorkflowExecutionResponse {
|
|
267
|
+
assert!(self.workflow_options.enable_eager_workflow_start);
|
|
268
|
+
worker
|
|
269
|
+
.eager_submit_wf(
|
|
270
|
+
self.task_queue_name.clone(),
|
|
271
|
+
wf_name.into(),
|
|
272
|
+
vec![],
|
|
273
|
+
self.workflow_options.clone(),
|
|
274
|
+
)
|
|
275
|
+
.await
|
|
276
|
+
.unwrap()
|
|
277
|
+
}
|
|
278
|
+
|
|
239
279
|
pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
|
|
240
280
|
let iw = self.initted_worker.get().expect(
|
|
241
281
|
"Worker must be initted before starting a workflow.\
|
|
@@ -275,7 +315,7 @@ impl CoreWfStarter {
|
|
|
275
315
|
let with_id = HistoryForReplay::new(history, wf_id);
|
|
276
316
|
let replay_worker = init_core_replay_preloaded(worker.task_queue(), [with_id]);
|
|
277
317
|
worker.with_new_core_worker(replay_worker);
|
|
278
|
-
worker.set_worker_interceptor(
|
|
318
|
+
worker.set_worker_interceptor(FailOnNondeterminismInterceptor {});
|
|
279
319
|
worker.run().await.unwrap();
|
|
280
320
|
Ok(())
|
|
281
321
|
}
|
|
@@ -366,23 +406,17 @@ pub struct TestWorker {
|
|
|
366
406
|
/// If set true (default), and a client is available, we will fetch workflow results to
|
|
367
407
|
/// determine when they have all completed.
|
|
368
408
|
pub fetch_results: bool,
|
|
369
|
-
iceptor: Option<TestWorkerCompletionIceptor>,
|
|
370
409
|
}
|
|
371
410
|
impl TestWorker {
|
|
372
411
|
/// Create a new test worker
|
|
373
412
|
pub fn new(core_worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
|
|
374
413
|
let inner = Worker::new_from_core(core_worker.clone(), task_queue);
|
|
375
|
-
let iceptor = TestWorkerCompletionIceptor::new(
|
|
376
|
-
TestWorkerShutdownCond::NoAutoShutdown,
|
|
377
|
-
Arc::new(inner.shutdown_handle()),
|
|
378
|
-
);
|
|
379
414
|
Self {
|
|
380
415
|
inner,
|
|
381
416
|
core_worker,
|
|
382
417
|
client: None,
|
|
383
418
|
started_workflows: Mutex::new(vec![]),
|
|
384
419
|
fetch_results: true,
|
|
385
|
-
iceptor: Some(iceptor),
|
|
386
420
|
}
|
|
387
421
|
}
|
|
388
422
|
|
|
@@ -443,6 +477,39 @@ impl TestWorker {
|
|
|
443
477
|
}
|
|
444
478
|
}
|
|
445
479
|
|
|
480
|
+
/// Similar to `submit_wf` but checking that the server returns the first
|
|
481
|
+
/// workflow task in the client response.
|
|
482
|
+
/// Note that this does not guarantee that the worker will execute this task eagerly.
|
|
483
|
+
pub async fn eager_submit_wf(
|
|
484
|
+
&self,
|
|
485
|
+
workflow_id: impl Into<String>,
|
|
486
|
+
workflow_type: impl Into<String>,
|
|
487
|
+
input: Vec<Payload>,
|
|
488
|
+
options: WorkflowOptions,
|
|
489
|
+
) -> Result<StartWorkflowExecutionResponse, anyhow::Error> {
|
|
490
|
+
let c = self.client.as_ref().context("client needed for eager wf")?;
|
|
491
|
+
let wfid = workflow_id.into();
|
|
492
|
+
let res = c
|
|
493
|
+
.start_workflow(
|
|
494
|
+
input,
|
|
495
|
+
self.inner.task_queue().to_string(),
|
|
496
|
+
wfid.clone(),
|
|
497
|
+
workflow_type.into(),
|
|
498
|
+
None,
|
|
499
|
+
options,
|
|
500
|
+
)
|
|
501
|
+
.await?;
|
|
502
|
+
res.eager_workflow_task
|
|
503
|
+
.as_ref()
|
|
504
|
+
.context("no eager workflow task")?;
|
|
505
|
+
self.started_workflows.lock().push(WorkflowExecutionInfo {
|
|
506
|
+
namespace: c.namespace().to_string(),
|
|
507
|
+
workflow_id: wfid,
|
|
508
|
+
run_id: Some(res.run_id.clone()),
|
|
509
|
+
});
|
|
510
|
+
Ok(res)
|
|
511
|
+
}
|
|
512
|
+
|
|
446
513
|
/// Runs until all expected workflows have completed
|
|
447
514
|
pub async fn run_until_done(&mut self) -> Result<(), anyhow::Error> {
|
|
448
515
|
self.run_until_done_intercepted(Option::<TestWorkerCompletionIceptor>::None)
|
|
@@ -452,9 +519,12 @@ impl TestWorker {
|
|
|
452
519
|
/// See [Self::run_until_done], but allows configuration of some low-level interception.
|
|
453
520
|
pub async fn run_until_done_intercepted(
|
|
454
521
|
&mut self,
|
|
455
|
-
|
|
522
|
+
next_interceptor: Option<impl WorkerInterceptor + 'static>,
|
|
456
523
|
) -> Result<(), anyhow::Error> {
|
|
457
|
-
let mut iceptor =
|
|
524
|
+
let mut iceptor = TestWorkerCompletionIceptor::new(
|
|
525
|
+
TestWorkerShutdownCond::NoAutoShutdown,
|
|
526
|
+
Arc::new(self.inner.shutdown_handle()),
|
|
527
|
+
);
|
|
458
528
|
// Automatically use results-based complete detection if we have a client
|
|
459
529
|
if self.fetch_results {
|
|
460
530
|
if let Some(c) = self.client.clone() {
|
|
@@ -464,9 +534,9 @@ impl TestWorker {
|
|
|
464
534
|
);
|
|
465
535
|
}
|
|
466
536
|
}
|
|
467
|
-
iceptor.next =
|
|
537
|
+
iceptor.next = next_interceptor.map(|i| Box::new(i) as Box<dyn WorkerInterceptor>);
|
|
468
538
|
let get_results_waiter = iceptor.wait_all_wfs();
|
|
469
|
-
self.inner.set_worker_interceptor(
|
|
539
|
+
self.inner.set_worker_interceptor(iceptor);
|
|
470
540
|
tokio::try_join!(self.inner.run(), get_results_waiter)?;
|
|
471
541
|
Ok(())
|
|
472
542
|
}
|
|
@@ -482,7 +552,6 @@ pub enum TestWorkerShutdownCond {
|
|
|
482
552
|
pub struct TestWorkerCompletionIceptor {
|
|
483
553
|
condition: TestWorkerShutdownCond,
|
|
484
554
|
shutdown_handle: Arc<dyn Fn()>,
|
|
485
|
-
every_activation: Option<BoxDynActivationHook>,
|
|
486
555
|
next: Option<Box<dyn WorkerInterceptor>>,
|
|
487
556
|
}
|
|
488
557
|
impl TestWorkerCompletionIceptor {
|
|
@@ -490,7 +559,6 @@ impl TestWorkerCompletionIceptor {
|
|
|
490
559
|
Self {
|
|
491
560
|
condition,
|
|
492
561
|
shutdown_handle,
|
|
493
|
-
every_activation: None,
|
|
494
562
|
next: None,
|
|
495
563
|
}
|
|
496
564
|
}
|
|
@@ -523,11 +591,8 @@ impl TestWorkerCompletionIceptor {
|
|
|
523
591
|
#[async_trait::async_trait(?Send)]
|
|
524
592
|
impl WorkerInterceptor for TestWorkerCompletionIceptor {
|
|
525
593
|
async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
|
|
526
|
-
if let Some(func) = self.every_activation.as_ref() {
|
|
527
|
-
func(completion);
|
|
528
|
-
}
|
|
529
594
|
if completion.has_execution_ending() {
|
|
530
|
-
|
|
595
|
+
debug!("Workflow {} says it's finishing", &completion.run_id);
|
|
531
596
|
}
|
|
532
597
|
if let Some(n) = self.next.as_ref() {
|
|
533
598
|
n.on_workflow_activation_completion(completion).await;
|
|
@@ -585,22 +650,24 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
585
650
|
.ok()
|
|
586
651
|
.map(|x| x.parse::<Url>().unwrap())
|
|
587
652
|
{
|
|
588
|
-
let opts =
|
|
589
|
-
url
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
ob.tracing(TraceExportConfig {
|
|
594
|
-
filter: filter_string.clone(),
|
|
595
|
-
exporter: TraceExporter::Otel(opts.clone()),
|
|
596
|
-
});
|
|
597
|
-
ob.metrics(MetricsExporter::Otel(opts));
|
|
653
|
+
let opts = OtelCollectorOptionsBuilder::default()
|
|
654
|
+
.url(url)
|
|
655
|
+
.build()
|
|
656
|
+
.unwrap();
|
|
657
|
+
ob.metrics(Arc::new(build_otlp_metric_exporter(opts).unwrap()) as Arc<dyn CoreMeter>);
|
|
598
658
|
}
|
|
599
659
|
if let Some(addr) = env::var(PROM_ENABLE_ENV_VAR)
|
|
600
660
|
.ok()
|
|
601
661
|
.map(|x| SocketAddr::new([127, 0, 0, 1].into(), x.parse().unwrap()))
|
|
602
662
|
{
|
|
603
|
-
|
|
663
|
+
let prom_info = start_prometheus_metric_exporter(
|
|
664
|
+
PrometheusExporterOptionsBuilder::default()
|
|
665
|
+
.socket_addr(addr)
|
|
666
|
+
.build()
|
|
667
|
+
.unwrap(),
|
|
668
|
+
)
|
|
669
|
+
.unwrap();
|
|
670
|
+
ob.metrics(prom_info.meter as Arc<dyn CoreMeter>);
|
|
604
671
|
}
|
|
605
672
|
ob.logging(Logger::Console {
|
|
606
673
|
filter: filter_string,
|
|
@@ -609,6 +676,7 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
609
676
|
.unwrap()
|
|
610
677
|
}
|
|
611
678
|
|
|
679
|
+
#[cfg(feature = "ephemeral-server")]
|
|
612
680
|
pub fn default_cached_download() -> EphemeralExe {
|
|
613
681
|
EphemeralExe::CachedDownload {
|
|
614
682
|
version: EphemeralExeVersion::SDKDefault {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
|
-
use std::{sync::Arc, time::Duration};
|
|
2
|
+
use std::{net::SocketAddr, sync::Arc, time::Duration};
|
|
3
3
|
use temporal_client::{WorkflowClientTrait, WorkflowOptions, WorkflowService};
|
|
4
|
-
use temporal_sdk_core::{init_worker, CoreRuntime};
|
|
5
|
-
use temporal_sdk_core_api::{
|
|
4
|
+
use temporal_sdk_core::{init_worker, telemetry::start_prometheus_metric_exporter, CoreRuntime};
|
|
5
|
+
use temporal_sdk_core_api::{
|
|
6
|
+
telemetry::{
|
|
7
|
+
metrics::{CoreMeter, MetricAttributes, MetricParameters},
|
|
8
|
+
PrometheusExporterOptionsBuilder, TelemetryOptions,
|
|
9
|
+
},
|
|
10
|
+
worker::WorkerConfigBuilder,
|
|
11
|
+
Worker,
|
|
12
|
+
};
|
|
6
13
|
use temporal_sdk_core_protos::{
|
|
7
14
|
coresdk::{
|
|
8
15
|
activity_result::ActivityExecutionResult,
|
|
@@ -23,7 +30,7 @@ use temporal_sdk_core_protos::{
|
|
|
23
30
|
use temporal_sdk_core_test_utils::{
|
|
24
31
|
get_integ_server_options, get_integ_telem_options, CoreWfStarter, NAMESPACE,
|
|
25
32
|
};
|
|
26
|
-
use tokio::{join, sync::Barrier};
|
|
33
|
+
use tokio::{join, sync::Barrier, task::AbortHandle};
|
|
27
34
|
|
|
28
35
|
static ANY_PORT: &str = "127.0.0.1:0";
|
|
29
36
|
|
|
@@ -31,15 +38,41 @@ async fn get_text(endpoint: String) -> String {
|
|
|
31
38
|
reqwest::get(endpoint).await.unwrap().text().await.unwrap()
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
struct AbortOnDrop {
|
|
42
|
+
ah: AbortHandle,
|
|
43
|
+
}
|
|
44
|
+
impl Drop for AbortOnDrop {
|
|
45
|
+
fn drop(&mut self) {
|
|
46
|
+
self.ah.abort();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn prom_metrics() -> (TelemetryOptions, SocketAddr, AbortOnDrop) {
|
|
51
|
+
let mut telemopts = get_integ_telem_options();
|
|
52
|
+
let prom_info = start_prometheus_metric_exporter(
|
|
53
|
+
PrometheusExporterOptionsBuilder::default()
|
|
54
|
+
.socket_addr(ANY_PORT.parse().unwrap())
|
|
55
|
+
.build()
|
|
56
|
+
.unwrap(),
|
|
57
|
+
)
|
|
58
|
+
.unwrap();
|
|
59
|
+
telemopts.metrics = Some(prom_info.meter as Arc<dyn CoreMeter>);
|
|
60
|
+
(
|
|
61
|
+
telemopts,
|
|
62
|
+
prom_info.bound_addr,
|
|
63
|
+
AbortOnDrop {
|
|
64
|
+
ah: prom_info.abort_handle,
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
34
69
|
#[tokio::test]
|
|
35
70
|
async fn prometheus_metrics_exported() {
|
|
36
|
-
let
|
|
37
|
-
telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
|
|
71
|
+
let (telemopts, addr, _aborter) = prom_metrics();
|
|
38
72
|
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
39
|
-
let addr = rt.telemetry().prom_port().unwrap();
|
|
40
73
|
let opts = get_integ_server_options();
|
|
41
74
|
let mut raw_client = opts
|
|
42
|
-
.connect_no_namespace(rt.
|
|
75
|
+
.connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
|
|
43
76
|
.await
|
|
44
77
|
.unwrap();
|
|
45
78
|
assert!(raw_client.get_client().capabilities().is_some());
|
|
@@ -56,15 +89,26 @@ async fn prometheus_metrics_exported() {
|
|
|
56
89
|
assert!(body.contains(
|
|
57
90
|
"temporal_request_latency_count{operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\"} 1"
|
|
58
91
|
));
|
|
92
|
+
// Verify counter names are appropriate (don't end w/ '_total')
|
|
93
|
+
assert!(body.contains("temporal_request{"));
|
|
94
|
+
// Verify non-temporal metrics meter does not prefix
|
|
95
|
+
let mm = rt.telemetry().get_metric_meter().unwrap();
|
|
96
|
+
let g = mm.inner.gauge(MetricParameters::from("mygauge"));
|
|
97
|
+
g.record(
|
|
98
|
+
42,
|
|
99
|
+
&MetricAttributes::OTel {
|
|
100
|
+
kvs: Arc::new(vec![]),
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
104
|
+
assert!(body.contains("\nmygauge 42"));
|
|
59
105
|
}
|
|
60
106
|
|
|
61
107
|
#[tokio::test]
|
|
62
108
|
async fn one_slot_worker_reports_available_slot() {
|
|
63
|
-
let
|
|
109
|
+
let (telemopts, addr, _aborter) = prom_metrics();
|
|
64
110
|
let tq = "one_slot_worker_tq";
|
|
65
|
-
telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
|
|
66
111
|
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
67
|
-
let addr = rt.telemetry().prom_port().unwrap();
|
|
68
112
|
|
|
69
113
|
let worker_cfg = WorkerConfigBuilder::default()
|
|
70
114
|
.namespace(NAMESPACE)
|
|
@@ -161,6 +205,16 @@ async fn one_slot_worker_reports_available_slot() {
|
|
|
161
205
|
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
162
206
|
worker_type=\"WorkflowWorker\"}} 2"
|
|
163
207
|
)));
|
|
208
|
+
assert!(body.contains(&format!(
|
|
209
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
210
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
211
|
+
worker_type=\"ActivityWorker\"}} 1"
|
|
212
|
+
)));
|
|
213
|
+
assert!(body.contains(&format!(
|
|
214
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
215
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
216
|
+
worker_type=\"LocalActivityWorker\"}} 1"
|
|
217
|
+
)));
|
|
164
218
|
|
|
165
219
|
// Start a workflow so that a task will get delivered
|
|
166
220
|
client
|
|
@@ -182,7 +236,7 @@ async fn one_slot_worker_reports_available_slot() {
|
|
|
182
236
|
wf_task_barr.wait().await;
|
|
183
237
|
|
|
184
238
|
// At this point the workflow task is outstanding, so there should be 0 slots, and
|
|
185
|
-
// the activities haven't started, so there should be 1 each.
|
|
239
|
+
// the activities haven't started, so there should still be 1 each.
|
|
186
240
|
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
187
241
|
assert!(body.contains(&format!(
|
|
188
242
|
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
@@ -264,10 +318,8 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
|
|
|
264
318
|
)]
|
|
265
319
|
completion: workflow_command::Variant,
|
|
266
320
|
) {
|
|
267
|
-
let
|
|
268
|
-
telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
|
|
321
|
+
let (telemopts, addr, _aborter) = prom_metrics();
|
|
269
322
|
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
270
|
-
let addr = rt.telemetry().prom_port().unwrap();
|
|
271
323
|
let mut starter =
|
|
272
324
|
CoreWfStarter::new_with_runtime("query_of_closed_workflow_doesnt_tick_terminal_metric", rt);
|
|
273
325
|
// Disable cache to ensure replay happens completely
|
|
@@ -275,7 +327,22 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
|
|
|
275
327
|
let worker = starter.get_worker().await;
|
|
276
328
|
let run_id = starter.start_wf().await;
|
|
277
329
|
let task = worker.poll_workflow_activation().await.unwrap();
|
|
330
|
+
// Fail wf task
|
|
331
|
+
worker
|
|
332
|
+
.complete_workflow_activation(WorkflowActivationCompletion::fail(
|
|
333
|
+
task.run_id,
|
|
334
|
+
"whatever".into(),
|
|
335
|
+
))
|
|
336
|
+
.await
|
|
337
|
+
.unwrap();
|
|
338
|
+
// Handle cache eviction
|
|
339
|
+
let task = worker.poll_workflow_activation().await.unwrap();
|
|
340
|
+
worker
|
|
341
|
+
.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
342
|
+
.await
|
|
343
|
+
.unwrap();
|
|
278
344
|
// Immediately complete the workflow
|
|
345
|
+
let task = worker.poll_workflow_activation().await.unwrap();
|
|
279
346
|
worker
|
|
280
347
|
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
281
348
|
task.run_id,
|
|
@@ -370,3 +437,31 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
|
|
|
370
437
|
.expect("Must find matching metric");
|
|
371
438
|
assert!(matching_line.ends_with('1'));
|
|
372
439
|
}
|
|
440
|
+
|
|
441
|
+
#[test]
|
|
442
|
+
fn runtime_new() {
|
|
443
|
+
let mut rt = CoreRuntime::new(
|
|
444
|
+
get_integ_telem_options(),
|
|
445
|
+
tokio::runtime::Builder::new_multi_thread(),
|
|
446
|
+
)
|
|
447
|
+
.unwrap();
|
|
448
|
+
let handle = rt.tokio_handle();
|
|
449
|
+
let _rt = handle.enter();
|
|
450
|
+
let (telemopts, addr, _aborter) = prom_metrics();
|
|
451
|
+
rt.telemetry_mut()
|
|
452
|
+
.attach_late_init_metrics(telemopts.metrics.unwrap());
|
|
453
|
+
let opts = get_integ_server_options();
|
|
454
|
+
handle.block_on(async {
|
|
455
|
+
let mut raw_client = opts
|
|
456
|
+
.connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
|
|
457
|
+
.await
|
|
458
|
+
.unwrap();
|
|
459
|
+
assert!(raw_client.get_client().capabilities().is_some());
|
|
460
|
+
let _ = raw_client
|
|
461
|
+
.list_namespaces(ListNamespacesRequest::default())
|
|
462
|
+
.await
|
|
463
|
+
.unwrap();
|
|
464
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
465
|
+
assert!(body.contains("temporal_request"));
|
|
466
|
+
});
|
|
467
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use futures::{prelude::stream::FuturesUnordered, FutureExt, StreamExt};
|
|
3
|
-
use
|
|
3
|
+
use futures_util::future::join_all;
|
|
4
|
+
use std::time::{Duration, Instant};
|
|
4
5
|
use temporal_client::WorkflowClientTrait;
|
|
5
6
|
use temporal_sdk_core_protos::{
|
|
6
7
|
coresdk::{
|
|
@@ -13,6 +14,7 @@ use temporal_sdk_core_protos::{
|
|
|
13
14
|
use temporal_sdk_core_test_utils::{
|
|
14
15
|
drain_pollers_and_shutdown, init_core_and_create_wf, WorkerTestHelpers,
|
|
15
16
|
};
|
|
17
|
+
use tokio::join;
|
|
16
18
|
|
|
17
19
|
#[tokio::test]
|
|
18
20
|
async fn simple_query_legacy() {
|
|
@@ -102,7 +104,7 @@ async fn simple_query_legacy() {
|
|
|
102
104
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
103
105
|
core.complete_execution(&task.run_id).await;
|
|
104
106
|
};
|
|
105
|
-
let (q_resp, _) =
|
|
107
|
+
let (q_resp, _) = join!(query_fut, workflow_completions_future);
|
|
106
108
|
// Ensure query response is as expected
|
|
107
109
|
assert_eq!(&q_resp.unwrap()[0].data, query_resp);
|
|
108
110
|
}
|
|
@@ -308,7 +310,176 @@ async fn fail_legacy_query() {
|
|
|
308
310
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
309
311
|
core.complete_execution(&task.run_id).await;
|
|
310
312
|
};
|
|
311
|
-
let (q_resp, _) =
|
|
313
|
+
let (q_resp, _) = join!(query_fut, workflow_completions_future);
|
|
312
314
|
// Ensure query response is a failure and has the right message
|
|
313
315
|
assert_eq!(q_resp.message(), query_err);
|
|
314
316
|
}
|
|
317
|
+
|
|
318
|
+
#[tokio::test]
|
|
319
|
+
async fn multiple_concurrent_queries_no_new_history() {
|
|
320
|
+
let mut starter = init_core_and_create_wf("multiple_concurrent_queries_no_new_history").await;
|
|
321
|
+
let core = starter.get_worker().await;
|
|
322
|
+
let workflow_id = starter.get_task_queue().to_string();
|
|
323
|
+
let started = Instant::now();
|
|
324
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
325
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
326
|
+
task.run_id.clone(),
|
|
327
|
+
vec![], // complete with no commands so that there will be no new history
|
|
328
|
+
))
|
|
329
|
+
.await
|
|
330
|
+
.unwrap();
|
|
331
|
+
let client = starter.get_client().await;
|
|
332
|
+
let num_queries = 10;
|
|
333
|
+
let query_futs = (1..=num_queries).map(|_| async {
|
|
334
|
+
client
|
|
335
|
+
.query_workflow_execution(
|
|
336
|
+
workflow_id.to_string(),
|
|
337
|
+
task.run_id.to_string(),
|
|
338
|
+
WorkflowQuery {
|
|
339
|
+
query_type: "myquery".to_string(),
|
|
340
|
+
query_args: Some(b"hi".into()),
|
|
341
|
+
header: None,
|
|
342
|
+
},
|
|
343
|
+
)
|
|
344
|
+
.await
|
|
345
|
+
.unwrap();
|
|
346
|
+
});
|
|
347
|
+
let complete_fut = async {
|
|
348
|
+
for _ in 1..=num_queries {
|
|
349
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
350
|
+
let query = assert_matches!(
|
|
351
|
+
task.jobs.as_slice(),
|
|
352
|
+
[WorkflowActivationJob {
|
|
353
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
354
|
+
}] => q
|
|
355
|
+
);
|
|
356
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
357
|
+
task.run_id,
|
|
358
|
+
QueryResult {
|
|
359
|
+
query_id: query.query_id.clone(),
|
|
360
|
+
variant: Some(
|
|
361
|
+
QuerySuccess {
|
|
362
|
+
response: Some("done".into()),
|
|
363
|
+
}
|
|
364
|
+
.into(),
|
|
365
|
+
),
|
|
366
|
+
}
|
|
367
|
+
.into(),
|
|
368
|
+
))
|
|
369
|
+
.await
|
|
370
|
+
.unwrap();
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
join!(join_all(query_futs), complete_fut);
|
|
374
|
+
// No need to properly finish
|
|
375
|
+
client
|
|
376
|
+
.terminate_workflow_execution(workflow_id, None)
|
|
377
|
+
.await
|
|
378
|
+
.unwrap();
|
|
379
|
+
// This test should not take a long time. Things can still work, but if it takes a long time
|
|
380
|
+
// that means we aren't buffering properly, and tasks are getting redelivered after timeout.
|
|
381
|
+
if started.elapsed() > Duration::from_secs(9) {
|
|
382
|
+
panic!("Should not have taken this long");
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
#[tokio::test]
|
|
387
|
+
async fn query_superseded_by_newer_wft_is_discarded() {
|
|
388
|
+
let mut starter = init_core_and_create_wf("query_superseded_by_newer_wft_is_discarded").await;
|
|
389
|
+
let core = starter.get_worker().await;
|
|
390
|
+
let workflow_id = starter.get_task_queue().to_string();
|
|
391
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
392
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
393
|
+
task.run_id.clone(),
|
|
394
|
+
vec![], // complete with no commands so that there will be no new history
|
|
395
|
+
))
|
|
396
|
+
.await
|
|
397
|
+
.unwrap();
|
|
398
|
+
let client = starter.get_client().await;
|
|
399
|
+
// Send two queries so that one of them is buffered
|
|
400
|
+
let query_futs = (1..=2).map(|_| async {
|
|
401
|
+
client
|
|
402
|
+
.query_workflow_execution(
|
|
403
|
+
workflow_id.to_string(),
|
|
404
|
+
task.run_id.to_string(),
|
|
405
|
+
WorkflowQuery {
|
|
406
|
+
query_type: "myquery".to_string(),
|
|
407
|
+
query_args: Some(b"hi".into()),
|
|
408
|
+
header: None,
|
|
409
|
+
},
|
|
410
|
+
)
|
|
411
|
+
.await
|
|
412
|
+
.unwrap();
|
|
413
|
+
});
|
|
414
|
+
let complete_fut = async {
|
|
415
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
416
|
+
let query = assert_matches!(
|
|
417
|
+
task.jobs.as_slice(),
|
|
418
|
+
[WorkflowActivationJob {
|
|
419
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
420
|
+
}] => q
|
|
421
|
+
);
|
|
422
|
+
// While handling the first query, signal the workflow so a new WFT is generated and the
|
|
423
|
+
// second query is still in the buffer
|
|
424
|
+
client
|
|
425
|
+
.signal_workflow_execution(
|
|
426
|
+
workflow_id.to_string(),
|
|
427
|
+
task.run_id.to_string(),
|
|
428
|
+
"blah".to_string(),
|
|
429
|
+
None,
|
|
430
|
+
None,
|
|
431
|
+
)
|
|
432
|
+
.await
|
|
433
|
+
.unwrap();
|
|
434
|
+
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
435
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
436
|
+
task.run_id,
|
|
437
|
+
QueryResult {
|
|
438
|
+
query_id: query.query_id.clone(),
|
|
439
|
+
variant: Some(
|
|
440
|
+
QuerySuccess {
|
|
441
|
+
response: Some("done".into()),
|
|
442
|
+
}
|
|
443
|
+
.into(),
|
|
444
|
+
),
|
|
445
|
+
}
|
|
446
|
+
.into(),
|
|
447
|
+
))
|
|
448
|
+
.await
|
|
449
|
+
.unwrap();
|
|
450
|
+
// We should get the signal activation since the in-buffer query should've been failed
|
|
451
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
452
|
+
assert_matches!(
|
|
453
|
+
task.jobs.as_slice(),
|
|
454
|
+
[WorkflowActivationJob {
|
|
455
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
456
|
+
}]
|
|
457
|
+
);
|
|
458
|
+
core.complete_execution(&task.run_id).await;
|
|
459
|
+
// Query will get retried by server since we fail the task w/ the stale query
|
|
460
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
461
|
+
let query = assert_matches!(
|
|
462
|
+
task.jobs.as_slice(),
|
|
463
|
+
[WorkflowActivationJob {
|
|
464
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
465
|
+
}] => q
|
|
466
|
+
);
|
|
467
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
468
|
+
task.run_id,
|
|
469
|
+
QueryResult {
|
|
470
|
+
query_id: query.query_id.clone(),
|
|
471
|
+
variant: Some(
|
|
472
|
+
QuerySuccess {
|
|
473
|
+
response: Some("done".into()),
|
|
474
|
+
}
|
|
475
|
+
.into(),
|
|
476
|
+
),
|
|
477
|
+
}
|
|
478
|
+
.into(),
|
|
479
|
+
))
|
|
480
|
+
.await
|
|
481
|
+
.unwrap();
|
|
482
|
+
};
|
|
483
|
+
join!(join_all(query_futs), complete_fut);
|
|
484
|
+
drain_pollers_and_shutdown(&core).await;
|
|
485
|
+
}
|