@temporalio/core-bridge 1.13.0 → 1.13.2
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 +239 -382
- package/Cargo.toml +11 -11
- package/lib/native.d.ts +10 -3
- package/package.json +3 -3
- 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/.cargo/config.toml +71 -11
- package/sdk-core/.clippy.toml +1 -0
- package/sdk-core/.github/workflows/heavy.yml +2 -0
- package/sdk-core/.github/workflows/per-pr.yml +50 -18
- package/sdk-core/ARCHITECTURE.md +44 -48
- package/sdk-core/Cargo.toml +26 -7
- package/sdk-core/README.md +4 -0
- package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
- package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
- package/sdk-core/arch_docs/sdks_intro.md +299 -0
- package/sdk-core/client/Cargo.toml +8 -7
- package/sdk-core/client/src/callback_based.rs +1 -2
- package/sdk-core/client/src/lib.rs +485 -299
- package/sdk-core/client/src/metrics.rs +32 -8
- package/sdk-core/client/src/proxy.rs +124 -5
- package/sdk-core/client/src/raw.rs +598 -307
- package/sdk-core/client/src/replaceable.rs +253 -0
- package/sdk-core/client/src/retry.rs +9 -6
- package/sdk-core/client/src/worker_registry/mod.rs +19 -3
- package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
- package/sdk-core/core/Cargo.toml +100 -31
- package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
- package/sdk-core/core/src/core_tests/mod.rs +2 -8
- package/sdk-core/core/src/core_tests/queries.rs +3 -5
- package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
- package/sdk-core/core/src/core_tests/updates.rs +4 -5
- package/sdk-core/core/src/core_tests/workers.rs +4 -3
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
- package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
- package/sdk-core/core/src/internal_flags.rs +11 -1
- package/sdk-core/core/src/lib.rs +50 -36
- package/sdk-core/core/src/pollers/mod.rs +5 -5
- package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
- package/sdk-core/core/src/protosext/mod.rs +13 -5
- package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
- package/sdk-core/core/src/retry_logic.rs +256 -108
- package/sdk-core/core/src/telemetry/metrics.rs +1 -0
- package/sdk-core/core/src/telemetry/mod.rs +8 -2
- package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
- package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
- package/sdk-core/core/src/test_help/mod.rs +10 -1100
- package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
- package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
- package/sdk-core/core/src/worker/activities.rs +10 -3
- package/sdk-core/core/src/worker/client/mocks.rs +3 -3
- package/sdk-core/core/src/worker/client.rs +130 -93
- package/sdk-core/core/src/worker/heartbeat.rs +12 -13
- package/sdk-core/core/src/worker/mod.rs +31 -21
- package/sdk-core/core/src/worker/nexus.rs +14 -3
- package/sdk-core/core/src/worker/slot_provider.rs +9 -0
- package/sdk-core/core/src/worker/tuner.rs +159 -0
- package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
- package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
- package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
- package/sdk-core/core-api/Cargo.toml +4 -4
- package/sdk-core/core-api/src/envconfig.rs +153 -54
- package/sdk-core/core-api/src/lib.rs +68 -0
- package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
- package/sdk-core/core-api/src/telemetry.rs +13 -0
- package/sdk-core/core-c-bridge/Cargo.toml +13 -8
- package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
- package/sdk-core/core-c-bridge/src/client.rs +462 -184
- package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
- package/sdk-core/core-c-bridge/src/lib.rs +1 -0
- package/sdk-core/core-c-bridge/src/random.rs +4 -4
- package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
- package/sdk-core/core-c-bridge/src/testing.rs +1 -4
- package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
- package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
- package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
- package/sdk-core/core-c-bridge/src/worker.rs +319 -66
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
- package/sdk-core/sdk/Cargo.toml +8 -2
- package/sdk-core/sdk/src/activity_context.rs +1 -1
- package/sdk-core/sdk/src/app_data.rs +1 -1
- package/sdk-core/sdk/src/interceptors.rs +1 -4
- package/sdk-core/sdk/src/lib.rs +1 -5
- package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
- package/sdk-core/sdk/src/workflow_future.rs +1 -1
- package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
- package/sdk-core/sdk-core-protos/build.rs +10 -23
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
- package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
- package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
- package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
- package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
- package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
- package/sdk-core/tests/cloud_tests.rs +10 -8
- package/sdk-core/tests/common/http_proxy.rs +134 -0
- package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
- package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
- package/sdk-core/tests/fuzzy_workflow.rs +1 -1
- package/sdk-core/tests/global_metric_tests.rs +8 -7
- package/sdk-core/tests/heavy_tests.rs +7 -3
- package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
- package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
- package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
- package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
- package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
- package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
- package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
- package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
- package/sdk-core/tests/main.rs +26 -17
- package/sdk-core/tests/manual_tests.rs +5 -1
- package/sdk-core/tests/runner.rs +22 -40
- package/sdk-core/tests/shared_tests/mod.rs +1 -1
- package/sdk-core/tests/shared_tests/priority.rs +1 -1
- package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
- package/src/client.rs +97 -20
- package/src/helpers/callbacks.rs +4 -4
- package/src/helpers/errors.rs +7 -1
- package/src/helpers/handles.rs +1 -0
- package/src/helpers/try_from_js.rs +4 -3
- package/src/lib.rs +3 -2
- package/src/metrics.rs +3 -0
- package/src/runtime.rs +5 -2
- package/src/worker.rs +9 -12
- package/ts/native.ts +13 -3
- package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
- package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
- package/sdk-core/core/src/core_tests/determinism.rs +0 -318
- package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
- package/sdk-core/test-utils/Cargo.toml +0 -38
- package/sdk-core/test-utils/src/histfetch.rs +0 -28
- package/sdk-core/test-utils/src/interceptors.rs +0 -46
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
use crate::prost_dur;
|
|
2
1
|
use std::time::Duration;
|
|
3
2
|
use temporal_sdk::{ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
|
|
4
|
-
use temporal_sdk_core_protos::{
|
|
3
|
+
use temporal_sdk_core_protos::{
|
|
4
|
+
coresdk::AsJsonPayloadExt, prost_dur, temporal::api::common::v1::RetryPolicy,
|
|
5
|
+
};
|
|
5
6
|
|
|
6
|
-
pub async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
|
|
7
|
+
pub(crate) async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
|
|
7
8
|
ctx.local_activity(LocalActivityOptions {
|
|
8
9
|
activity_type: "delay".to_string(),
|
|
9
10
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use crate::common::CoreWfStarter;
|
|
1
2
|
use futures_util::{FutureExt, StreamExt, sink, stream::FuturesUnordered};
|
|
2
3
|
use rand::{Rng, SeedableRng, prelude::Distribution, rngs::SmallRng};
|
|
3
4
|
use std::{future, time::Duration};
|
|
@@ -6,7 +7,6 @@ use temporal_sdk::{
|
|
|
6
7
|
ActContext, ActivityError, ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult,
|
|
7
8
|
};
|
|
8
9
|
use temporal_sdk_core_protos::coresdk::{AsJsonPayloadExt, FromJsonPayloadExt, IntoPayloadsExt};
|
|
9
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
10
10
|
use tokio_util::sync::CancellationToken;
|
|
11
11
|
|
|
12
12
|
const FUZZY_SIG: &str = "fuzzy_sig";
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// All non-main.rs tests ignore dead common code so that the linter doesn't complain about about it.
|
|
2
|
+
#[allow(dead_code)]
|
|
3
|
+
mod common;
|
|
4
|
+
|
|
5
|
+
use common::CoreWfStarter;
|
|
1
6
|
use parking_lot::Mutex;
|
|
2
7
|
use std::{sync::Arc, time::Duration};
|
|
3
8
|
use temporal_sdk_core::{
|
|
@@ -7,7 +12,6 @@ use temporal_sdk_core::{
|
|
|
7
12
|
use temporal_sdk_core_api::telemetry::{
|
|
8
13
|
Logger, OtelCollectorOptionsBuilder, TelemetryOptionsBuilder, metrics::CoreMeter,
|
|
9
14
|
};
|
|
10
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
11
15
|
use tracing::Level;
|
|
12
16
|
use tracing_subscriber::fmt::MakeWriter;
|
|
13
17
|
|
|
@@ -99,18 +103,15 @@ async fn otel_errors_logged_as_errors() {
|
|
|
99
103
|
);
|
|
100
104
|
assert!(
|
|
101
105
|
log_str.contains("@@@@@@@@@"),
|
|
102
|
-
"Expected fallback log not found in logs: {}",
|
|
103
|
-
log_str
|
|
106
|
+
"Expected fallback log not found in logs: {log_str}",
|
|
104
107
|
);
|
|
105
108
|
// TODO: OTel just doesn't actually log useful errors right now 🤷, see issues at top of test
|
|
106
109
|
assert!(
|
|
107
110
|
log_str.contains("ERROR"),
|
|
108
|
-
"Expected ERROR log not found in logs: {}",
|
|
109
|
-
log_str
|
|
111
|
+
"Expected ERROR log not found in logs: {log_str}",
|
|
110
112
|
);
|
|
111
113
|
assert!(
|
|
112
114
|
log_str.contains("Metrics exporter otlp failed with the grpc server returns error"),
|
|
113
|
-
"Expected an OTel exporter error message in logs: {}",
|
|
114
|
-
log_str
|
|
115
|
+
"Expected an OTel exporter error message in logs: {log_str}",
|
|
115
116
|
);
|
|
116
117
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// All non-main.rs tests ignore dead common code so that the linter doesn't complain about about it.
|
|
2
|
+
#[allow(dead_code)]
|
|
3
|
+
mod common;
|
|
4
|
+
|
|
5
|
+
use common::{
|
|
6
|
+
CoreWfStarter, init_integ_telem, prom_metrics, rand_6_chars, workflows::la_problem_workflow,
|
|
7
|
+
};
|
|
1
8
|
use futures_util::{
|
|
2
9
|
StreamExt,
|
|
3
10
|
future::{AbortHandle, Abortable, join_all},
|
|
@@ -18,9 +25,6 @@ use temporal_sdk_core_protos::{
|
|
|
18
25
|
coresdk::{AsJsonPayloadExt, workflow_commands::ActivityCancellationType},
|
|
19
26
|
temporal::api::enums::v1::WorkflowIdReusePolicy,
|
|
20
27
|
};
|
|
21
|
-
use temporal_sdk_core_test_utils::{
|
|
22
|
-
CoreWfStarter, init_integ_telem, prom_metrics, rand_6_chars, workflows::la_problem_workflow,
|
|
23
|
-
};
|
|
24
28
|
|
|
25
29
|
mod fuzzy_workflow;
|
|
26
30
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use crate::common::{CoreWfStarter, NAMESPACE, get_integ_server_options, http_proxy::HttpProxy};
|
|
1
2
|
use assert_matches::assert_matches;
|
|
2
3
|
use futures_util::{FutureExt, future::BoxFuture};
|
|
3
4
|
use http_body_util::Full;
|
|
@@ -14,7 +15,8 @@ use std::{
|
|
|
14
15
|
time::Duration,
|
|
15
16
|
};
|
|
16
17
|
use temporal_client::{
|
|
17
|
-
Namespace, RETRYABLE_ERROR_CODES, RetryConfig, WorkflowClientTrait,
|
|
18
|
+
HttpConnectProxyOptions, Namespace, RETRYABLE_ERROR_CODES, RetryConfig, WorkflowClientTrait,
|
|
19
|
+
WorkflowService,
|
|
18
20
|
};
|
|
19
21
|
use temporal_sdk_core_protos::temporal::api::{
|
|
20
22
|
cloud::cloudservice::v1::GetNamespaceRequest,
|
|
@@ -23,13 +25,14 @@ use temporal_sdk_core_protos::temporal::api::{
|
|
|
23
25
|
RespondActivityTaskCanceledResponse,
|
|
24
26
|
},
|
|
25
27
|
};
|
|
26
|
-
|
|
28
|
+
#[cfg(unix)]
|
|
29
|
+
use tokio::net::UnixListener;
|
|
27
30
|
use tokio::{
|
|
28
31
|
net::TcpListener,
|
|
29
32
|
sync::{mpsc::UnboundedSender, oneshot},
|
|
30
33
|
};
|
|
31
34
|
use tonic::{
|
|
32
|
-
Code, Request, Status,
|
|
35
|
+
Code, IntoRequest, Request, Status,
|
|
33
36
|
body::Body,
|
|
34
37
|
codegen::{Service, http::Response},
|
|
35
38
|
server::NamedService,
|
|
@@ -53,10 +56,13 @@ async fn can_use_retry_raw_client() {
|
|
|
53
56
|
let opts = get_integ_server_options();
|
|
54
57
|
let mut client = opts.connect_no_namespace(None).await.unwrap();
|
|
55
58
|
client
|
|
56
|
-
.describe_namespace(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
.describe_namespace(
|
|
60
|
+
DescribeNamespaceRequest {
|
|
61
|
+
namespace: NAMESPACE.to_string(),
|
|
62
|
+
..Default::default()
|
|
63
|
+
}
|
|
64
|
+
.into_request(),
|
|
65
|
+
)
|
|
60
66
|
.await
|
|
61
67
|
.unwrap();
|
|
62
68
|
}
|
|
@@ -74,12 +80,15 @@ async fn per_call_timeout_respected_whole_client() {
|
|
|
74
80
|
let mut raw_client = opts.connect_no_namespace(None).await.unwrap();
|
|
75
81
|
let mut hm = HashMap::new();
|
|
76
82
|
hm.insert("grpc-timeout".to_string(), "0S".to_string());
|
|
77
|
-
raw_client.get_client().set_headers(hm);
|
|
83
|
+
raw_client.get_client().set_headers(hm).unwrap();
|
|
78
84
|
let err = raw_client
|
|
79
|
-
.describe_namespace(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
.describe_namespace(
|
|
86
|
+
DescribeNamespaceRequest {
|
|
87
|
+
namespace: NAMESPACE.to_string(),
|
|
88
|
+
..Default::default()
|
|
89
|
+
}
|
|
90
|
+
.into_request(),
|
|
91
|
+
)
|
|
83
92
|
.await
|
|
84
93
|
.unwrap_err();
|
|
85
94
|
assert_matches!(err.code(), Code::DeadlineExceeded | Code::Cancelled);
|
|
@@ -110,7 +119,7 @@ struct GenericService<F> {
|
|
|
110
119
|
}
|
|
111
120
|
impl<F> Service<tonic::codegen::http::Request<Body>> for GenericService<F>
|
|
112
121
|
where
|
|
113
|
-
F: FnMut() -> BoxFuture<'static, Response<Body>>,
|
|
122
|
+
F: FnMut(tonic::codegen::http::Request<Body>) -> BoxFuture<'static, Response<Body>>,
|
|
114
123
|
{
|
|
115
124
|
type Response = Response<Body>;
|
|
116
125
|
type Error = Infallible;
|
|
@@ -132,7 +141,7 @@ where
|
|
|
132
141
|
.to_string(),
|
|
133
142
|
)
|
|
134
143
|
.unwrap();
|
|
135
|
-
let r = (self.response_maker)();
|
|
144
|
+
let r = (self.response_maker)(req);
|
|
136
145
|
async move { Ok(r.await) }.boxed()
|
|
137
146
|
}
|
|
138
147
|
}
|
|
@@ -149,7 +158,11 @@ struct FakeServer {
|
|
|
149
158
|
|
|
150
159
|
async fn fake_server<F>(response_maker: F) -> FakeServer
|
|
151
160
|
where
|
|
152
|
-
F: FnMut() -> BoxFuture<'static, Response<Body>>
|
|
161
|
+
F: FnMut(tonic::codegen::http::Request<Body>) -> BoxFuture<'static, Response<Body>>
|
|
162
|
+
+ Clone
|
|
163
|
+
+ Send
|
|
164
|
+
+ Sync
|
|
165
|
+
+ 'static,
|
|
153
166
|
{
|
|
154
167
|
let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
|
|
155
168
|
let (header_tx, header_rx) = tokio::sync::mpsc::unbounded_channel();
|
|
@@ -191,7 +204,7 @@ impl FakeServer {
|
|
|
191
204
|
|
|
192
205
|
#[tokio::test]
|
|
193
206
|
async fn timeouts_respected_one_call_fake_server() {
|
|
194
|
-
let mut fs = fake_server(
|
|
207
|
+
let mut fs = fake_server(|_| async { Response::new(Body::empty()) }.boxed()).await;
|
|
195
208
|
let header_rx = &mut fs.header_rx;
|
|
196
209
|
|
|
197
210
|
let mut opts = get_integ_server_options();
|
|
@@ -260,7 +273,7 @@ async fn non_retryable_errors() {
|
|
|
260
273
|
Code::Unauthenticated,
|
|
261
274
|
Code::Unimplemented,
|
|
262
275
|
] {
|
|
263
|
-
let mut fs = fake_server(move
|
|
276
|
+
let mut fs = fake_server(move |_| {
|
|
264
277
|
let s = Status::new(code, "bla").into_http();
|
|
265
278
|
async { s }.boxed()
|
|
266
279
|
})
|
|
@@ -295,7 +308,7 @@ async fn retryable_errors() {
|
|
|
295
308
|
.filter(|p| p != &Code::ResourceExhausted)
|
|
296
309
|
{
|
|
297
310
|
let count = Arc::new(AtomicUsize::new(0));
|
|
298
|
-
let mut fs = fake_server(move
|
|
311
|
+
let mut fs = fake_server(move |_| {
|
|
299
312
|
let prev = count.fetch_add(1, Ordering::Relaxed);
|
|
300
313
|
let r = if prev < 3 {
|
|
301
314
|
Status::new(code, "bla").into_http()
|
|
@@ -339,7 +352,7 @@ async fn namespace_header_attached_to_relevant_calls() {
|
|
|
339
352
|
.add_service(GenericService {
|
|
340
353
|
header_to_parse: "Temporal-Namespace",
|
|
341
354
|
header_tx,
|
|
342
|
-
response_maker:
|
|
355
|
+
response_maker: |_| async { Response::new(Body::empty()) }.boxed(),
|
|
343
356
|
})
|
|
344
357
|
.serve_with_incoming_shutdown(
|
|
345
358
|
tokio_stream::wrappers::TcpListenerStream::new(listener),
|
|
@@ -402,17 +415,91 @@ async fn cloud_ops_test() {
|
|
|
402
415
|
hm.insert("temporal-cloud-api-version".to_string(), api_version);
|
|
403
416
|
hm
|
|
404
417
|
});
|
|
405
|
-
let
|
|
406
|
-
let cloud_client = client.
|
|
418
|
+
let client = opts.connect_no_namespace(None).await.unwrap().into_inner();
|
|
419
|
+
let mut cloud_client = client.cloud_svc();
|
|
407
420
|
let res = cloud_client
|
|
408
|
-
.get_namespace(
|
|
409
|
-
|
|
410
|
-
|
|
421
|
+
.get_namespace(
|
|
422
|
+
GetNamespaceRequest {
|
|
423
|
+
namespace: namespace.clone(),
|
|
424
|
+
}
|
|
425
|
+
.into_request(),
|
|
426
|
+
)
|
|
411
427
|
.await
|
|
412
428
|
.unwrap();
|
|
413
429
|
assert_eq!(res.into_inner().namespace.unwrap().namespace, namespace);
|
|
414
430
|
}
|
|
415
431
|
|
|
432
|
+
#[tokio::test]
|
|
433
|
+
async fn http_proxy() {
|
|
434
|
+
// Create server
|
|
435
|
+
let call_count = Arc::new(AtomicUsize::new(0));
|
|
436
|
+
let call_count_cloned = call_count.clone();
|
|
437
|
+
let server = fake_server(move |_| {
|
|
438
|
+
call_count_cloned.fetch_add(1, Ordering::SeqCst);
|
|
439
|
+
async { Response::new(Body::empty()) }.boxed()
|
|
440
|
+
})
|
|
441
|
+
.await;
|
|
442
|
+
|
|
443
|
+
// Create HTTP TCP proxy
|
|
444
|
+
let tcp_proxy_listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
445
|
+
let tcp_proxy_addr = tcp_proxy_listener.local_addr().unwrap();
|
|
446
|
+
let tcp_proxy = HttpProxy::spawn_tcp(tcp_proxy_listener);
|
|
447
|
+
|
|
448
|
+
// General client options
|
|
449
|
+
let mut opts = get_integ_server_options();
|
|
450
|
+
opts.retry_config = RetryConfig::no_retries();
|
|
451
|
+
opts.skip_get_system_info = true;
|
|
452
|
+
|
|
453
|
+
// Connect client with no proxy and make call and confirm reached
|
|
454
|
+
opts.target_url = format!("http://127.0.0.1:{}", server.addr.port())
|
|
455
|
+
.parse()
|
|
456
|
+
.unwrap();
|
|
457
|
+
let client = opts.connect("my-namespace", None).await.unwrap();
|
|
458
|
+
let _ = client.list_namespaces().await;
|
|
459
|
+
assert!(call_count.load(Ordering::SeqCst) == 1);
|
|
460
|
+
assert!(tcp_proxy.hit_count() == 0);
|
|
461
|
+
|
|
462
|
+
// Connect client to proxy and make call and confirm reached
|
|
463
|
+
opts.http_connect_proxy = Some(HttpConnectProxyOptions {
|
|
464
|
+
target_addr: tcp_proxy_addr.to_string(),
|
|
465
|
+
basic_auth: None,
|
|
466
|
+
});
|
|
467
|
+
let proxied_client = opts.connect("my-namespace", None).await.unwrap();
|
|
468
|
+
let _ = proxied_client.list_namespaces().await;
|
|
469
|
+
assert!(call_count.load(Ordering::SeqCst) == 2);
|
|
470
|
+
assert!(tcp_proxy.hit_count() == 1);
|
|
471
|
+
|
|
472
|
+
// Test Unix socket too only in Unix environments
|
|
473
|
+
#[cfg(unix)]
|
|
474
|
+
{
|
|
475
|
+
// Create temp socket path
|
|
476
|
+
let mut sock_path = std::env::temp_dir();
|
|
477
|
+
sock_path.push(format!("http-proxy-test-{}.sock", std::process::id()));
|
|
478
|
+
// Remove if there just in case
|
|
479
|
+
let _ = std::fs::remove_file(&sock_path);
|
|
480
|
+
|
|
481
|
+
// Create unix-socket-based proxy
|
|
482
|
+
let unix_proxy = HttpProxy::spawn_unix(UnixListener::bind(&sock_path).unwrap());
|
|
483
|
+
|
|
484
|
+
// Connect client to proxy and make call and confirm reached
|
|
485
|
+
opts.http_connect_proxy = Some(HttpConnectProxyOptions {
|
|
486
|
+
target_addr: format!("unix:{}", sock_path.to_str().unwrap()),
|
|
487
|
+
basic_auth: None,
|
|
488
|
+
});
|
|
489
|
+
let proxied_client = opts.connect("my-namespace", None).await.unwrap();
|
|
490
|
+
let _ = proxied_client.list_namespaces().await;
|
|
491
|
+
assert!(call_count.load(Ordering::SeqCst) == 3);
|
|
492
|
+
assert!(unix_proxy.hit_count() == 1);
|
|
493
|
+
|
|
494
|
+
// Shutdown unix proxy
|
|
495
|
+
unix_proxy.shutdown();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Shutdown server and proxy
|
|
499
|
+
server.shutdown().await;
|
|
500
|
+
tcp_proxy.shutdown();
|
|
501
|
+
}
|
|
502
|
+
|
|
416
503
|
fn make_ok_response<T>(message: T) -> Response<Body>
|
|
417
504
|
where
|
|
418
505
|
T: Message,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
use crate::common::{INTEG_CLIENT_IDENTITY, INTEG_CLIENT_NAME, INTEG_CLIENT_VERSION, NAMESPACE};
|
|
1
2
|
use futures_util::{TryStreamExt, stream};
|
|
2
3
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
3
4
|
use temporal_client::{ClientOptionsBuilder, TestService, WorkflowService};
|
|
4
5
|
use temporal_sdk_core::ephemeral_server::{
|
|
5
6
|
EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporalDevServerConfigBuilder,
|
|
7
|
+
default_cached_download,
|
|
6
8
|
};
|
|
7
9
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
|
|
8
|
-
use
|
|
10
|
+
use tonic::IntoRequest;
|
|
9
11
|
use url::Url;
|
|
10
12
|
|
|
11
13
|
#[tokio::test]
|
|
@@ -136,27 +138,30 @@ fn fixed_cached_download(version: &str) -> EphemeralExe {
|
|
|
136
138
|
async fn assert_ephemeral_server(server: &EphemeralServer) {
|
|
137
139
|
// Connect and describe namespace
|
|
138
140
|
let mut client = ClientOptionsBuilder::default()
|
|
139
|
-
.identity(
|
|
141
|
+
.identity(INTEG_CLIENT_IDENTITY.to_string())
|
|
140
142
|
.target_url(Url::try_from(&*format!("http://{}", server.target)).unwrap())
|
|
141
|
-
.client_name(
|
|
142
|
-
.client_version(
|
|
143
|
+
.client_name(INTEG_CLIENT_NAME.to_string())
|
|
144
|
+
.client_version(INTEG_CLIENT_VERSION.to_string())
|
|
143
145
|
.build()
|
|
144
146
|
.unwrap()
|
|
145
147
|
.connect_no_namespace(None)
|
|
146
148
|
.await
|
|
147
149
|
.unwrap();
|
|
148
150
|
let resp = client
|
|
149
|
-
.describe_namespace(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
.describe_namespace(
|
|
152
|
+
DescribeNamespaceRequest {
|
|
153
|
+
namespace: NAMESPACE.to_string(),
|
|
154
|
+
..Default::default()
|
|
155
|
+
}
|
|
156
|
+
.into_request(),
|
|
157
|
+
)
|
|
153
158
|
.await
|
|
154
159
|
.unwrap();
|
|
155
160
|
assert!(resp.into_inner().namespace_info.unwrap().name == "default");
|
|
156
161
|
|
|
157
162
|
// If it has test service, make sure we can use it too
|
|
158
163
|
if server.has_test_service {
|
|
159
|
-
let resp = client.get_current_time(()).await.unwrap();
|
|
164
|
+
let resp = client.get_current_time(().into_request()).await.unwrap();
|
|
160
165
|
// Make sure it's within 5 mins of now
|
|
161
166
|
let resp_seconds = resp.get_ref().time.as_ref().unwrap().seconds as u64;
|
|
162
167
|
let curr_seconds = SystemTime::now()
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
use crate::common::{CoreWfStarter, init_core_and_create_wf};
|
|
1
2
|
use assert_matches::assert_matches;
|
|
2
3
|
use std::time::Duration;
|
|
3
4
|
use temporal_client::{WfClientExt, WorkflowOptions};
|
|
4
5
|
use temporal_sdk::{ActContext, ActivityOptions, WfContext};
|
|
6
|
+
use temporal_sdk_core::test_help::{WorkerTestHelpers, drain_pollers_and_shutdown};
|
|
5
7
|
use temporal_sdk_core_protos::{
|
|
6
8
|
DEFAULT_ACTIVITY_TYPE,
|
|
7
9
|
coresdk::{
|
|
@@ -14,14 +16,12 @@ use temporal_sdk_core_protos::{
|
|
|
14
16
|
workflow_commands::{ActivityCancellationType, ScheduleActivity},
|
|
15
17
|
workflow_completion::WorkflowActivationCompletion,
|
|
16
18
|
},
|
|
19
|
+
prost_dur,
|
|
17
20
|
temporal::api::{
|
|
18
21
|
common::v1::{Payload, RetryPolicy},
|
|
19
22
|
enums::v1::TimeoutType,
|
|
20
23
|
},
|
|
21
|
-
|
|
22
|
-
use temporal_sdk_core_test_utils::{
|
|
23
|
-
CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, init_core_and_create_wf,
|
|
24
|
-
schedule_activity_cmd,
|
|
24
|
+
test_utils::schedule_activity_cmd,
|
|
25
25
|
};
|
|
26
26
|
use tokio::time::sleep;
|
|
27
27
|
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
use crate::
|
|
1
|
+
use crate::{
|
|
2
|
+
common::{
|
|
3
|
+
ANY_PORT, CoreWfStarter, NAMESPACE, OTEL_URL_ENV_VAR, PROMETHEUS_QUERY_API,
|
|
4
|
+
get_integ_server_options, get_integ_telem_options, prom_metrics,
|
|
5
|
+
},
|
|
6
|
+
integ_tests::mk_nexus_endpoint,
|
|
7
|
+
};
|
|
2
8
|
use anyhow::anyhow;
|
|
3
9
|
use assert_matches::assert_matches;
|
|
4
10
|
use std::{
|
|
@@ -24,7 +30,7 @@ use temporal_sdk_core_api::{
|
|
|
24
30
|
errors::PollError,
|
|
25
31
|
telemetry::{
|
|
26
32
|
HistogramBucketOverrides, OtelCollectorOptionsBuilder, OtlpProtocol,
|
|
27
|
-
PrometheusExporterOptionsBuilder, TelemetryOptionsBuilder,
|
|
33
|
+
PrometheusExporterOptionsBuilder, TaskQueueLabelStrategy, TelemetryOptionsBuilder,
|
|
28
34
|
metrics::{
|
|
29
35
|
CoreMeter, CounterBase, Gauge, GaugeBase, HistogramBase, MetricKeyValue,
|
|
30
36
|
MetricParameters, MetricParametersBuilder, NewAttributes,
|
|
@@ -49,6 +55,7 @@ use temporal_sdk_core_protos::{
|
|
|
49
55
|
},
|
|
50
56
|
workflow_completion::WorkflowActivationCompletion,
|
|
51
57
|
},
|
|
58
|
+
prost_dur,
|
|
52
59
|
temporal::api::{
|
|
53
60
|
common::v1::RetryPolicy,
|
|
54
61
|
enums::v1::{NexusHandlerErrorRetryBehavior, WorkflowIdReusePolicy},
|
|
@@ -62,11 +69,8 @@ use temporal_sdk_core_protos::{
|
|
|
62
69
|
workflowservice::v1::{DescribeNamespaceRequest, ListNamespacesRequest},
|
|
63
70
|
},
|
|
64
71
|
};
|
|
65
|
-
use temporal_sdk_core_test_utils::{
|
|
66
|
-
ANY_PORT, CoreWfStarter, NAMESPACE, OTEL_URL_ENV_VAR, PROMETHEUS_QUERY_API,
|
|
67
|
-
get_integ_server_options, get_integ_telem_options, prom_metrics,
|
|
68
|
-
};
|
|
69
72
|
use tokio::{join, sync::Barrier};
|
|
73
|
+
use tonic::IntoRequest;
|
|
70
74
|
use url::Url;
|
|
71
75
|
|
|
72
76
|
pub(crate) async fn get_text(endpoint: String) -> String {
|
|
@@ -103,7 +107,7 @@ async fn prometheus_metrics_exported(
|
|
|
103
107
|
assert!(raw_client.get_client().capabilities().is_some());
|
|
104
108
|
|
|
105
109
|
let _ = raw_client
|
|
106
|
-
.list_namespaces(ListNamespacesRequest::default())
|
|
110
|
+
.list_namespaces(ListNamespacesRequest::default().into_request())
|
|
107
111
|
.await
|
|
108
112
|
.unwrap();
|
|
109
113
|
|
|
@@ -535,7 +539,7 @@ fn runtime_new() {
|
|
|
535
539
|
.unwrap();
|
|
536
540
|
assert!(raw_client.get_client().capabilities().is_some());
|
|
537
541
|
let _ = raw_client
|
|
538
|
-
.list_namespaces(ListNamespacesRequest::default())
|
|
542
|
+
.list_namespaces(ListNamespacesRequest::default().into_request())
|
|
539
543
|
.await
|
|
540
544
|
.unwrap();
|
|
541
545
|
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
@@ -629,9 +633,12 @@ async fn request_fail_codes() {
|
|
|
629
633
|
.unwrap();
|
|
630
634
|
|
|
631
635
|
// Describe namespace w/ invalid argument (unset namespace field)
|
|
632
|
-
WorkflowService::describe_namespace(
|
|
633
|
-
|
|
634
|
-
.
|
|
636
|
+
WorkflowService::describe_namespace(
|
|
637
|
+
&mut client,
|
|
638
|
+
DescribeNamespaceRequest::default().into_request(),
|
|
639
|
+
)
|
|
640
|
+
.await
|
|
641
|
+
.unwrap_err();
|
|
635
642
|
|
|
636
643
|
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
637
644
|
let matching_line = body
|
|
@@ -674,9 +681,12 @@ async fn request_fail_codes_otel() {
|
|
|
674
681
|
|
|
675
682
|
for _ in 0..10 {
|
|
676
683
|
// Describe namespace w/ invalid argument (unset namespace field)
|
|
677
|
-
WorkflowService::describe_namespace(
|
|
678
|
-
|
|
679
|
-
.
|
|
684
|
+
WorkflowService::describe_namespace(
|
|
685
|
+
&mut client,
|
|
686
|
+
DescribeNamespaceRequest::default().into_request(),
|
|
687
|
+
)
|
|
688
|
+
.await
|
|
689
|
+
.unwrap_err();
|
|
680
690
|
|
|
681
691
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
682
692
|
}
|
|
@@ -1313,3 +1323,93 @@ async fn prometheus_label_nonsense() {
|
|
|
1313
1323
|
assert!(body.contains("some_counter{thing=\"foo\"} 2"));
|
|
1314
1324
|
assert!(body.contains("some_counter{blerp=\"baz\"} 2"));
|
|
1315
1325
|
}
|
|
1326
|
+
|
|
1327
|
+
#[rstest::rstest]
|
|
1328
|
+
#[tokio::test]
|
|
1329
|
+
async fn sticky_queue_label_strategy(
|
|
1330
|
+
#[values(
|
|
1331
|
+
TaskQueueLabelStrategy::UseNormal,
|
|
1332
|
+
TaskQueueLabelStrategy::UseNormalAndSticky
|
|
1333
|
+
)]
|
|
1334
|
+
strategy: TaskQueueLabelStrategy,
|
|
1335
|
+
) {
|
|
1336
|
+
let (mut telemopts, addr, _aborter) = prom_metrics(Some(
|
|
1337
|
+
PrometheusExporterOptionsBuilder::default()
|
|
1338
|
+
.socket_addr(ANY_PORT.parse().unwrap())
|
|
1339
|
+
.build()
|
|
1340
|
+
.unwrap(),
|
|
1341
|
+
));
|
|
1342
|
+
telemopts.task_queue_label_strategy = strategy;
|
|
1343
|
+
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
1344
|
+
let wf_name = format!("sticky_queue_label_strategy_{strategy:?}");
|
|
1345
|
+
let mut starter = CoreWfStarter::new_with_runtime(&wf_name, rt);
|
|
1346
|
+
// Enable sticky queues by setting a reasonable cache size
|
|
1347
|
+
starter.worker_config.max_cached_workflows(10_usize);
|
|
1348
|
+
starter.worker_config.no_remote_activities(true);
|
|
1349
|
+
let task_queue = starter.get_task_queue().to_owned();
|
|
1350
|
+
let mut worker = starter.worker().await;
|
|
1351
|
+
|
|
1352
|
+
worker.register_wf(wf_name.clone(), |ctx: WfContext| async move {
|
|
1353
|
+
ctx.timer(Duration::from_millis(1)).await;
|
|
1354
|
+
Ok(().into())
|
|
1355
|
+
});
|
|
1356
|
+
worker
|
|
1357
|
+
.submit_wf(
|
|
1358
|
+
wf_name.clone(),
|
|
1359
|
+
wf_name,
|
|
1360
|
+
vec![],
|
|
1361
|
+
WorkflowOptions {
|
|
1362
|
+
enable_eager_workflow_start: false,
|
|
1363
|
+
..Default::default()
|
|
1364
|
+
},
|
|
1365
|
+
)
|
|
1366
|
+
.await
|
|
1367
|
+
.unwrap();
|
|
1368
|
+
worker.run_until_done().await.unwrap();
|
|
1369
|
+
|
|
1370
|
+
// Give metrics time to be recorded
|
|
1371
|
+
tokio::time::sleep(Duration::from_millis(200)).await;
|
|
1372
|
+
|
|
1373
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
1374
|
+
|
|
1375
|
+
let poll_metrics: Vec<_> = body
|
|
1376
|
+
.lines()
|
|
1377
|
+
.filter(|l| {
|
|
1378
|
+
l.contains("temporal_long_request")
|
|
1379
|
+
&& l.contains("operation=\"PollWorkflowTaskQueue\"")
|
|
1380
|
+
&& l.contains(&format!("namespace=\"{NAMESPACE}\""))
|
|
1381
|
+
})
|
|
1382
|
+
.collect();
|
|
1383
|
+
|
|
1384
|
+
assert!(!poll_metrics.is_empty(), "Should have poll metrics");
|
|
1385
|
+
|
|
1386
|
+
match strategy {
|
|
1387
|
+
TaskQueueLabelStrategy::UseNormalAndSticky => {
|
|
1388
|
+
// With UseNormalAndSticky, we should see sticky queue names
|
|
1389
|
+
let has_sticky = poll_metrics.iter().any(|l| {
|
|
1390
|
+
l.contains("task_queue=")
|
|
1391
|
+
&& l.contains("WorkflowTask")
|
|
1392
|
+
&& !l.contains(&format!("task_queue=\"{task_queue}\""))
|
|
1393
|
+
});
|
|
1394
|
+
|
|
1395
|
+
assert!(
|
|
1396
|
+
has_sticky,
|
|
1397
|
+
"With UseNormalAndSticky, should see sticky queue names in metrics. Metrics:\n{}",
|
|
1398
|
+
poll_metrics.join("\n")
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
TaskQueueLabelStrategy::UseNormal => {
|
|
1402
|
+
// With UseNormal, ALL metrics should use the normal queue name
|
|
1403
|
+
for l in &poll_metrics {
|
|
1404
|
+
if l.contains("task_queue=") && l.contains("WorkflowTask") {
|
|
1405
|
+
assert!(
|
|
1406
|
+
l.contains(&format!("task_queue=\"{task_queue}\"")),
|
|
1407
|
+
"With UseNormal, all workflow task_queue labels should use normal name. Found: {}",
|
|
1408
|
+
l
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
_ => unreachable!("Test only covers UseNormal and UseNormalAndSticky"),
|
|
1414
|
+
}
|
|
1415
|
+
}
|