@temporalio/core-bridge 0.19.2 → 0.20.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 +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- 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/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +207 -108
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +139 -151
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//! to replay canned histories. It should be used by Lang SDKs to provide replay capabilities to
|
|
3
3
|
//! users during testing.
|
|
4
4
|
|
|
5
|
-
use crate::{
|
|
5
|
+
use crate::{worker::client::mocks::mock_manual_workflow_client, WorkerClientBag};
|
|
6
6
|
use futures::FutureExt;
|
|
7
7
|
use std::{
|
|
8
8
|
sync::{
|
|
@@ -11,154 +11,26 @@ use std::{
|
|
|
11
11
|
},
|
|
12
12
|
time::Duration,
|
|
13
13
|
};
|
|
14
|
-
use
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
errors::{
|
|
20
|
-
CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
|
|
21
|
-
WorkerRegistrationError,
|
|
22
|
-
},
|
|
23
|
-
worker::WorkerConfig,
|
|
24
|
-
Core, CoreLog,
|
|
25
|
-
};
|
|
26
|
-
use temporal_sdk_core_protos::{
|
|
27
|
-
coresdk::{
|
|
28
|
-
activity_task::ActivityTask, workflow_activation::WorkflowActivation,
|
|
29
|
-
workflow_completion::WorkflowActivationCompletion, ActivityHeartbeat,
|
|
30
|
-
ActivityTaskCompletion,
|
|
31
|
-
},
|
|
32
|
-
temporal::api::{
|
|
33
|
-
common::v1::WorkflowExecution,
|
|
34
|
-
history::v1::History,
|
|
35
|
-
workflowservice::v1::{
|
|
36
|
-
RespondWorkflowTaskCompletedResponse, RespondWorkflowTaskFailedResponse,
|
|
37
|
-
StartWorkflowExecutionResponse,
|
|
38
|
-
},
|
|
14
|
+
use temporal_sdk_core_protos::temporal::api::{
|
|
15
|
+
common::v1::WorkflowExecution,
|
|
16
|
+
history::v1::History,
|
|
17
|
+
workflowservice::v1::{
|
|
18
|
+
RespondWorkflowTaskCompletedResponse, RespondWorkflowTaskFailedResponse,
|
|
39
19
|
},
|
|
40
20
|
};
|
|
41
|
-
|
|
42
21
|
pub use temporal_sdk_core_protos::{
|
|
43
22
|
default_wes_attribs, HistoryInfo, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE,
|
|
44
23
|
};
|
|
45
24
|
|
|
46
|
-
/// Create a
|
|
47
|
-
/// canned history.
|
|
48
|
-
pub fn init_core_replay(opts: TelemetryOptions) -> ReplayCoreImpl {
|
|
49
|
-
let shared_mock_gateway = mock_gateway();
|
|
50
|
-
let init_opts = CoreInitOptionsBuilder::default()
|
|
51
|
-
.gateway_opts(shared_mock_gateway.get_options().clone())
|
|
52
|
-
.telemetry_opts(opts)
|
|
53
|
-
.build()
|
|
54
|
-
.expect("replay core options init properly");
|
|
55
|
-
let replay_core =
|
|
56
|
-
init_mock_gateway(init_opts, shared_mock_gateway).expect("init replay core works");
|
|
57
|
-
ReplayCoreImpl { inner: replay_core }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/// An extension of the [Core] trait to be used for testing workflows against canned histories.
|
|
61
|
-
pub trait ReplayCore: Core {
|
|
62
|
-
/// Make a fake worker which will use the provided history to simulate poll responses containing
|
|
63
|
-
/// that entire history. The configuration should have a unique task queue name.
|
|
64
|
-
///
|
|
65
|
-
/// Note that some of the worker config options do not apply, and some will be overridden.
|
|
66
|
-
/// Replay workers always are cached, have only 1 poller, and do not poll for activities.
|
|
67
|
-
fn make_replay_worker(
|
|
68
|
-
&self,
|
|
69
|
-
config: WorkerConfig,
|
|
70
|
-
history: &History,
|
|
71
|
-
) -> Result<(), anyhow::Error>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/// Implements [ReplayCore] functionality
|
|
75
|
-
pub struct ReplayCoreImpl {
|
|
76
|
-
pub(crate) inner: CoreSDK,
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
impl ReplayCore for ReplayCoreImpl {
|
|
80
|
-
fn make_replay_worker(
|
|
81
|
-
&self,
|
|
82
|
-
mut config: WorkerConfig,
|
|
83
|
-
history: &History,
|
|
84
|
-
) -> Result<(), anyhow::Error> {
|
|
85
|
-
let mock_g = mock_gateway_from_history(history, config.task_queue.clone());
|
|
86
|
-
config.max_cached_workflows = 1;
|
|
87
|
-
config.max_concurrent_wft_polls = 1;
|
|
88
|
-
config.no_remote_activities = true;
|
|
89
|
-
self.inner
|
|
90
|
-
.register_replay_worker(config, Arc::new(mock_g), history)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
#[async_trait::async_trait]
|
|
95
|
-
impl Core for ReplayCoreImpl {
|
|
96
|
-
fn register_worker(&self, _config: WorkerConfig) -> Result<(), WorkerRegistrationError> {
|
|
97
|
-
panic!("Do not use `register_worker` with a replay core instance")
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async fn poll_workflow_activation(
|
|
101
|
-
&self,
|
|
102
|
-
task_queue: &str,
|
|
103
|
-
) -> Result<WorkflowActivation, PollWfError> {
|
|
104
|
-
self.inner.poll_workflow_activation(task_queue).await
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async fn poll_activity_task(
|
|
108
|
-
&self,
|
|
109
|
-
task_queue: &str,
|
|
110
|
-
) -> Result<ActivityTask, PollActivityError> {
|
|
111
|
-
self.inner.poll_activity_task(task_queue).await
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async fn complete_workflow_activation(
|
|
115
|
-
&self,
|
|
116
|
-
completion: WorkflowActivationCompletion,
|
|
117
|
-
) -> Result<(), CompleteWfError> {
|
|
118
|
-
self.inner.complete_workflow_activation(completion).await
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async fn complete_activity_task(
|
|
122
|
-
&self,
|
|
123
|
-
completion: ActivityTaskCompletion,
|
|
124
|
-
) -> Result<(), CompleteActivityError> {
|
|
125
|
-
self.inner.complete_activity_task(completion).await
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
fn record_activity_heartbeat(&self, _details: ActivityHeartbeat) {
|
|
129
|
-
// do nothing
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
fn request_workflow_eviction(&self, task_queue: &str, run_id: &str) {
|
|
133
|
-
self.inner.request_workflow_eviction(task_queue, run_id)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
fn server_gateway(&self) -> Arc<dyn ServerGatewayApis + Send + Sync> {
|
|
137
|
-
self.inner.server_gateway()
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async fn shutdown(&self) {
|
|
141
|
-
self.inner.shutdown().await
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async fn shutdown_worker(&self, task_queue: &str) {
|
|
145
|
-
self.inner.shutdown_worker(task_queue).await
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
fn fetch_buffered_logs(&self) -> Vec<CoreLog> {
|
|
149
|
-
self.inner.fetch_buffered_logs()
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/// Create a mock gateway which can be used by a replay worker to serve up canned history.
|
|
25
|
+
/// Create a mock client which can be used by a replay worker to serve up canned history.
|
|
154
26
|
/// It will return the entire history in one workflow task, after that it will return default
|
|
155
27
|
/// responses (with a 10s wait). If a workflow task failure is sent to the mock, it will send
|
|
156
28
|
/// the complete response again.
|
|
157
|
-
pub fn
|
|
29
|
+
pub(crate) fn mock_client_from_history(
|
|
158
30
|
history: &History,
|
|
159
31
|
task_queue: impl Into<String>,
|
|
160
|
-
) ->
|
|
161
|
-
let mut mg =
|
|
32
|
+
) -> WorkerClientBag {
|
|
33
|
+
let mut mg = mock_manual_workflow_client();
|
|
162
34
|
|
|
163
35
|
let hist_info = HistoryInfo::new_from_history(history, None).unwrap();
|
|
164
36
|
let wf = WorkflowExecution {
|
|
@@ -166,17 +38,6 @@ pub fn mock_gateway_from_history(
|
|
|
166
38
|
run_id: hist_info.orig_run_id().to_string(),
|
|
167
39
|
};
|
|
168
40
|
|
|
169
|
-
let wf_clone = wf.clone();
|
|
170
|
-
mg.expect_start_workflow().returning(move |_, _, _, _, _| {
|
|
171
|
-
let wf_clone = wf_clone.clone();
|
|
172
|
-
async move {
|
|
173
|
-
Ok(StartWorkflowExecutionResponse {
|
|
174
|
-
run_id: wf_clone.run_id.clone(),
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
.boxed()
|
|
178
|
-
});
|
|
179
|
-
|
|
180
41
|
let did_send = Arc::new(AtomicBool::new(false));
|
|
181
42
|
let did_send_clone = did_send.clone();
|
|
182
43
|
let tq = task_queue.into();
|
|
@@ -206,5 +67,5 @@ pub fn mock_gateway_from_history(
|
|
|
206
67
|
async move { Ok(RespondWorkflowTaskFailedResponse {}) }.boxed()
|
|
207
68
|
});
|
|
208
69
|
|
|
209
|
-
mg
|
|
70
|
+
WorkerClientBag::new(Box::new(mg), "fake_namespace".to_string())
|
|
210
71
|
}
|
|
@@ -8,7 +8,7 @@ use opentelemetry::{
|
|
|
8
8
|
},
|
|
9
9
|
KeyValue,
|
|
10
10
|
};
|
|
11
|
-
use std::{sync::Arc, time::Duration};
|
|
11
|
+
use std::{borrow::Cow, sync::Arc, time::Duration};
|
|
12
12
|
|
|
13
13
|
/// Used to track context associated with metrics, and record/update them
|
|
14
14
|
///
|
|
@@ -31,6 +31,11 @@ impl MetricsContext {
|
|
|
31
31
|
Self::new(vec![KeyValue::new(KEY_NAMESPACE, namespace)])
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
pub(crate) fn with_task_q(mut self, tq: String) -> Self {
|
|
35
|
+
Arc::make_mut(&mut self.kvs).push(task_queue(tq));
|
|
36
|
+
self
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
/// Extend an existing metrics context with new attributes
|
|
35
40
|
pub(crate) fn with_new_attrs(&self, new_kvs: impl IntoIterator<Item = KeyValue>) -> Self {
|
|
36
41
|
let mut kvs = self.kvs.clone();
|
|
@@ -119,6 +124,11 @@ impl MetricsContext {
|
|
|
119
124
|
WORKER_REGISTERED.add(1, &self.kvs);
|
|
120
125
|
}
|
|
121
126
|
|
|
127
|
+
/// Record current number of available task slots. Context should have worker type set.
|
|
128
|
+
pub(crate) fn available_task_slots(&self, num: usize) {
|
|
129
|
+
TASK_SLOTS_AVAILABLE.record(num as u64, &self.kvs)
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
/// Record current number of pollers. Context should include poller type / task queue tag.
|
|
123
133
|
pub(crate) fn record_num_pollers(&self, num: usize) {
|
|
124
134
|
NUM_POLLERS.record(num as u64, &self.kvs);
|
|
@@ -174,6 +184,7 @@ const KEY_WF_TYPE: &str = "workflow_type";
|
|
|
174
184
|
const KEY_TASK_QUEUE: &str = "task_queue";
|
|
175
185
|
const KEY_ACT_TYPE: &str = "activity_type";
|
|
176
186
|
const KEY_POLLER_TYPE: &str = "poller_type";
|
|
187
|
+
const KEY_WORKER_TYPE: &str = "worker_type";
|
|
177
188
|
|
|
178
189
|
pub(crate) fn workflow_poller() -> KeyValue {
|
|
179
190
|
KeyValue::new(KEY_POLLER_TYPE, "workflow_task")
|
|
@@ -193,6 +204,24 @@ pub(crate) fn activity_type(ty: String) -> KeyValue {
|
|
|
193
204
|
pub(crate) fn workflow_type(ty: String) -> KeyValue {
|
|
194
205
|
KeyValue::new(KEY_WF_TYPE, ty)
|
|
195
206
|
}
|
|
207
|
+
pub(crate) const fn workflow_worker_type() -> KeyValue {
|
|
208
|
+
KeyValue {
|
|
209
|
+
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
210
|
+
value: opentelemetry::Value::String(Cow::Borrowed("WorkflowWorker")),
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
pub(crate) const fn activity_worker_type() -> KeyValue {
|
|
214
|
+
KeyValue {
|
|
215
|
+
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
216
|
+
value: opentelemetry::Value::String(Cow::Borrowed("ActivityWorker")),
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
pub(crate) const fn local_activity_worker_type() -> KeyValue {
|
|
220
|
+
KeyValue {
|
|
221
|
+
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
222
|
+
value: opentelemetry::Value::String(Cow::Borrowed("LocalActivityWorker")),
|
|
223
|
+
}
|
|
224
|
+
}
|
|
196
225
|
|
|
197
226
|
tm!(ctr, WF_COMPLETED_COUNTER, "workflow_completed");
|
|
198
227
|
tm!(ctr, WF_CANCELED_COUNTER, "workflow_canceled");
|
|
@@ -248,6 +277,8 @@ tm!(vr_u64, ACT_EXEC_LATENCY, ACT_EXEC_LATENCY_NAME);
|
|
|
248
277
|
tm!(ctr, WORKER_REGISTERED, "worker_start");
|
|
249
278
|
const NUM_POLLERS_NAME: &str = "num_pollers";
|
|
250
279
|
tm!(vr_u64, NUM_POLLERS, NUM_POLLERS_NAME);
|
|
280
|
+
const TASK_SLOTS_AVAILABLE_NAME: &str = "worker_task_slots_available";
|
|
281
|
+
tm!(vr_u64, TASK_SLOTS_AVAILABLE, TASK_SLOTS_AVAILABLE_NAME);
|
|
251
282
|
|
|
252
283
|
tm!(ctr, STICKY_CACHE_HIT, "sticky_cache_hit");
|
|
253
284
|
tm!(ctr, STICKY_CACHE_MISS, "sticky_cache_miss");
|
|
@@ -305,7 +336,9 @@ impl AggregatorSelector for SDKAggSelector {
|
|
|
305
336
|
if *descriptor.instrument_kind() == InstrumentKind::ValueRecorder {
|
|
306
337
|
// Some recorders are just gauges
|
|
307
338
|
match descriptor.name() {
|
|
308
|
-
STICKY_CACHE_SIZE_NAME | NUM_POLLERS_NAME =>
|
|
339
|
+
STICKY_CACHE_SIZE_NAME | NUM_POLLERS_NAME | TASK_SLOTS_AVAILABLE_NAME => {
|
|
340
|
+
return Some(Arc::new(last_value()))
|
|
341
|
+
}
|
|
309
342
|
_ => (),
|
|
310
343
|
}
|
|
311
344
|
|
|
@@ -4,13 +4,14 @@ mod prometheus_server;
|
|
|
4
4
|
use crate::{
|
|
5
5
|
log_export::CoreExportLogger,
|
|
6
6
|
telemetry::{metrics::SDKAggSelector, prometheus_server::PromServer},
|
|
7
|
-
CoreLog,
|
|
7
|
+
CoreLog, METRIC_METER,
|
|
8
8
|
};
|
|
9
9
|
use itertools::Itertools;
|
|
10
10
|
use log::LevelFilter;
|
|
11
11
|
use once_cell::sync::OnceCell;
|
|
12
12
|
use opentelemetry::{
|
|
13
13
|
global,
|
|
14
|
+
metrics::Meter,
|
|
14
15
|
sdk::{metrics::PushController, trace::Config, Resource},
|
|
15
16
|
util::tokio_interval_stream,
|
|
16
17
|
KeyValue,
|
|
@@ -18,6 +19,7 @@ use opentelemetry::{
|
|
|
18
19
|
use opentelemetry_otlp::WithExportConfig;
|
|
19
20
|
use parking_lot::{const_mutex, Mutex};
|
|
20
21
|
use std::{collections::VecDeque, net::SocketAddr, time::Duration};
|
|
22
|
+
use temporal_sdk_core_api::CoreTelemetry;
|
|
21
23
|
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
|
|
22
24
|
use url::Url;
|
|
23
25
|
|
|
@@ -27,6 +29,14 @@ static DEFAULT_FILTER: &str = "temporal_sdk_core=INFO";
|
|
|
27
29
|
static GLOBAL_TELEM_DAT: OnceCell<GlobalTelemDat> = OnceCell::new();
|
|
28
30
|
static TELETM_MUTEX: Mutex<()> = const_mutex(());
|
|
29
31
|
|
|
32
|
+
fn default_resource_kvs() -> &'static [KeyValue] {
|
|
33
|
+
static INSTANCE: OnceCell<[KeyValue; 1]> = OnceCell::new();
|
|
34
|
+
INSTANCE.get_or_init(|| [KeyValue::new("service.name", TELEM_SERVICE_NAME)])
|
|
35
|
+
}
|
|
36
|
+
fn default_resource() -> Resource {
|
|
37
|
+
Resource::new(default_resource_kvs().iter().cloned())
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
/// Telemetry configuration options. Construct with [TelemetryOptionsBuilder]
|
|
31
41
|
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
32
42
|
#[non_exhaustive]
|
|
@@ -56,6 +66,10 @@ pub struct TelemetryOptions {
|
|
|
56
66
|
/// to the OTel collector if it is also set, only traces will be.
|
|
57
67
|
#[builder(setter(into, strip_option), default)]
|
|
58
68
|
pub prometheus_export_bind_address: Option<SocketAddr>,
|
|
69
|
+
/// If set, no resources are dedicated to telemetry and no metrics or traces are emited.
|
|
70
|
+
/// Supercedes all other options.
|
|
71
|
+
#[builder(default)]
|
|
72
|
+
pub totally_disable: bool,
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
impl Default for TelemetryOptions {
|
|
@@ -66,7 +80,7 @@ impl Default for TelemetryOptions {
|
|
|
66
80
|
|
|
67
81
|
/// Things that need to not be dropped while telemetry is ongoing
|
|
68
82
|
#[derive(Default)]
|
|
69
|
-
pub
|
|
83
|
+
pub struct GlobalTelemDat {
|
|
70
84
|
metric_push_controller: Option<PushController>,
|
|
71
85
|
core_export_logger: Option<CoreExportLogger>,
|
|
72
86
|
runtime: Option<tokio::runtime::Runtime>,
|
|
@@ -87,14 +101,24 @@ impl GlobalTelemDat {
|
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
impl CoreTelemetry for GlobalTelemDat {
|
|
105
|
+
fn fetch_buffered_logs(&self) -> Vec<CoreLog> {
|
|
106
|
+
fetch_global_buffered_logs()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fn get_metric_meter(&self) -> Option<&Meter> {
|
|
110
|
+
if GLOBAL_TELEM_DAT.get().is_some() {
|
|
111
|
+
return Some(&METRIC_METER);
|
|
112
|
+
}
|
|
113
|
+
None
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Initialize tracing subscribers/output and logging export. If this function is called more than
|
|
118
|
+
/// once, subsequent calls do nothing.
|
|
93
119
|
///
|
|
94
120
|
/// See [TelemetryOptions] docs for more on configuration.
|
|
95
|
-
pub
|
|
96
|
-
opts: &TelemetryOptions,
|
|
97
|
-
) -> Result<&'static GlobalTelemDat, anyhow::Error> {
|
|
121
|
+
pub fn telemetry_init(opts: &TelemetryOptions) -> Result<&'static GlobalTelemDat, anyhow::Error> {
|
|
98
122
|
// TODO: Per-layer filtering has been implemented but does not yet support
|
|
99
123
|
// env-filter. When it does, allow filtering logs/telemetry separately.
|
|
100
124
|
|
|
@@ -116,6 +140,15 @@ pub(crate) fn telemetry_init(
|
|
|
116
140
|
// Ensure closure captures the mutex guard
|
|
117
141
|
let _ = &*guard;
|
|
118
142
|
|
|
143
|
+
if opts.totally_disable {
|
|
144
|
+
return Ok(GlobalTelemDat {
|
|
145
|
+
metric_push_controller: None,
|
|
146
|
+
core_export_logger: None,
|
|
147
|
+
runtime: None,
|
|
148
|
+
prom_srv: None,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
119
152
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
|
120
153
|
.thread_name("telemetry")
|
|
121
154
|
.worker_threads(2)
|
|
@@ -146,11 +179,7 @@ pub(crate) fn telemetry_init(
|
|
|
146
179
|
|
|
147
180
|
if let Some(otel_url) = opts.otel_collector_url.as_ref() {
|
|
148
181
|
runtime.block_on(async {
|
|
149
|
-
let tracer_cfg =
|
|
150
|
-
Config::default().with_resource(Resource::new(vec![KeyValue::new(
|
|
151
|
-
"service.name",
|
|
152
|
-
TELEM_SERVICE_NAME,
|
|
153
|
-
)]));
|
|
182
|
+
let tracer_cfg = Config::default().with_resource(default_resource());
|
|
154
183
|
let tracer = opentelemetry_otlp::new_pipeline()
|
|
155
184
|
.tracing()
|
|
156
185
|
.with_exporter(
|
|
@@ -168,6 +197,7 @@ pub(crate) fn telemetry_init(
|
|
|
168
197
|
.metrics(|f| runtime.spawn(f), tokio_interval_stream)
|
|
169
198
|
.with_aggregator_selector(SDKAggSelector)
|
|
170
199
|
.with_period(Duration::from_secs(1))
|
|
200
|
+
.with_resource(default_resource_kvs().iter().cloned())
|
|
171
201
|
.with_exporter(
|
|
172
202
|
// No joke exporter builder literally not cloneable for some insane
|
|
173
203
|
// reason
|
|
@@ -210,8 +240,9 @@ pub(crate) fn telemetry_init(
|
|
|
210
240
|
.expect("Telemetry initialization panicked")
|
|
211
241
|
}
|
|
212
242
|
|
|
213
|
-
/// Returned buffered logs for export to lang from the global logging instance
|
|
214
|
-
|
|
243
|
+
/// Returned buffered logs for export to lang from the global logging instance.
|
|
244
|
+
/// If [telemetry_init] has not been called, always returns an empty vec.
|
|
245
|
+
pub fn fetch_global_buffered_logs() -> Vec<CoreLog> {
|
|
215
246
|
if let Some(loggr) = GLOBAL_TELEM_DAT
|
|
216
247
|
.get()
|
|
217
248
|
.and_then(|gd| gd.core_export_logger.as_ref())
|
|
@@ -227,9 +258,10 @@ pub(crate) fn fetch_global_buffered_logs() -> Vec<CoreLog> {
|
|
|
227
258
|
pub(crate) fn test_telem_console() {
|
|
228
259
|
telemetry_init(&TelemetryOptions {
|
|
229
260
|
otel_collector_url: None,
|
|
230
|
-
tracing_filter: "temporal_sdk_core=DEBUG".to_string(),
|
|
261
|
+
tracing_filter: "temporal_sdk_core=DEBUG,temporal_sdk=DEBUG".to_string(),
|
|
231
262
|
log_forwarding_level: LevelFilter::Off,
|
|
232
263
|
prometheus_export_bind_address: None,
|
|
264
|
+
totally_disable: false,
|
|
233
265
|
})
|
|
234
266
|
.unwrap();
|
|
235
267
|
}
|
|
@@ -242,6 +274,7 @@ pub(crate) fn test_telem_collector() {
|
|
|
242
274
|
tracing_filter: "temporal_sdk_core=DEBUG".to_string(),
|
|
243
275
|
log_forwarding_level: LevelFilter::Off,
|
|
244
276
|
prometheus_export_bind_address: None,
|
|
277
|
+
totally_disable: false,
|
|
245
278
|
})
|
|
246
279
|
.unwrap();
|
|
247
280
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
use crate::telemetry::
|
|
1
|
+
use crate::telemetry::{
|
|
2
|
+
default_resource,
|
|
3
|
+
metrics::{SDKAggSelector, DEFAULT_MS_BUCKETS},
|
|
4
|
+
};
|
|
2
5
|
use hyper::{
|
|
3
6
|
header::CONTENT_TYPE,
|
|
4
7
|
service::{make_service_fn, service_fn},
|
|
5
8
|
Body, Method, Request, Response, Server,
|
|
6
9
|
};
|
|
7
|
-
use opentelemetry::
|
|
8
|
-
|
|
9
|
-
metrics::MetricsError,
|
|
10
|
-
sdk::{export::metrics::ExportKindSelector, metrics::controllers},
|
|
11
|
-
};
|
|
12
|
-
use opentelemetry_prometheus::PrometheusExporter;
|
|
10
|
+
use opentelemetry::metrics::MetricsError;
|
|
11
|
+
use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
|
|
13
12
|
use prometheus::{Encoder, TextEncoder};
|
|
14
|
-
use std::{convert::Infallible, net::SocketAddr, sync::Arc
|
|
13
|
+
use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
|
15
14
|
|
|
16
15
|
/// Exposes prometheus metrics for scraping
|
|
17
16
|
pub(super) struct PromServer {
|
|
@@ -21,7 +20,13 @@ pub(super) struct PromServer {
|
|
|
21
20
|
|
|
22
21
|
impl PromServer {
|
|
23
22
|
pub fn new(addr: SocketAddr) -> Result<Self, MetricsError> {
|
|
24
|
-
let exporter =
|
|
23
|
+
let exporter = ExporterBuilder::default()
|
|
24
|
+
.with_default_histogram_boundaries(DEFAULT_MS_BUCKETS.to_vec())
|
|
25
|
+
.with_aggregator_selector(SDKAggSelector)
|
|
26
|
+
.with_host(addr.ip().to_string())
|
|
27
|
+
.with_port(addr.port())
|
|
28
|
+
.with_resource(default_resource())
|
|
29
|
+
.try_init()?;
|
|
25
30
|
Ok(Self {
|
|
26
31
|
exporter: Arc::new(exporter),
|
|
27
32
|
addr,
|
|
@@ -66,29 +71,3 @@ async fn metrics_req(
|
|
|
66
71
|
};
|
|
67
72
|
Ok(response)
|
|
68
73
|
}
|
|
69
|
-
|
|
70
|
-
/// There is no easy way to customize the aggregation selector for the prom exporter so this
|
|
71
|
-
/// code is some dupe of the exporter's try_init code.
|
|
72
|
-
pub fn create_exporter() -> Result<PrometheusExporter, MetricsError> {
|
|
73
|
-
let controller_builder = controllers::pull(
|
|
74
|
-
Box::new(SDKAggSelector),
|
|
75
|
-
Box::new(ExportKindSelector::Cumulative),
|
|
76
|
-
)
|
|
77
|
-
.with_cache_period(Duration::from_secs(0))
|
|
78
|
-
.with_memory(true);
|
|
79
|
-
let controller = controller_builder.build();
|
|
80
|
-
|
|
81
|
-
global::set_meter_provider(controller.provider());
|
|
82
|
-
|
|
83
|
-
// No choice bro https://github.com/open-telemetry/opentelemetry-rust/issues/633
|
|
84
|
-
#[allow(deprecated)]
|
|
85
|
-
PrometheusExporter::new(
|
|
86
|
-
prometheus::Registry::new(),
|
|
87
|
-
controller,
|
|
88
|
-
DEFAULT_MS_BUCKETS.to_vec(),
|
|
89
|
-
DEFAULT_MS_BUCKETS.to_vec(),
|
|
90
|
-
// Host and port aren't actually used for anything
|
|
91
|
-
"".to_string(),
|
|
92
|
-
0,
|
|
93
|
-
)
|
|
94
|
-
}
|