@temporalio/core-bridge 1.3.0 → 1.4.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 +117 -212
- package/index.d.ts +8 -2
- package/package.json +2 -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/pipeline.yml +2 -0
- package/sdk-core/.cargo/config.toml +1 -1
- package/sdk-core/bridge-ffi/src/lib.rs +2 -2
- package/sdk-core/client/Cargo.toml +1 -1
- package/sdk-core/client/src/lib.rs +16 -11
- package/sdk-core/client/src/metrics.rs +13 -11
- package/sdk-core/client/src/raw.rs +1 -2
- package/sdk-core/client/src/retry.rs +57 -42
- package/sdk-core/core/Cargo.toml +12 -8
- package/sdk-core/core/src/core_tests/activity_tasks.rs +65 -40
- package/sdk-core/core/src/ephemeral_server/mod.rs +19 -3
- package/sdk-core/core/src/lib.rs +2 -2
- package/sdk-core/core/src/pollers/mod.rs +2 -0
- package/sdk-core/core/src/telemetry/metrics.rs +48 -39
- package/sdk-core/core/src/telemetry/mod.rs +53 -22
- package/sdk-core/core/src/telemetry/prometheus_server.rs +17 -13
- package/sdk-core/core/src/worker/client/mocks.rs +1 -0
- package/sdk-core/core/src/worker/workflow/mod.rs +4 -1
- package/sdk-core/core-api/Cargo.toml +1 -1
- package/sdk-core/test-utils/src/lib.rs +21 -2
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +27 -40
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -0
- package/sdk-core/tests/integ_tests/queries_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +1 -5
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +8 -2
- package/sdk-core/tests/main.rs +7 -0
- package/sdk-core/tests/runner.rs +93 -0
- package/src/conversions.rs +19 -3
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
use super::TELEM_SERVICE_NAME;
|
|
2
2
|
use crate::telemetry::GLOBAL_TELEM_DAT;
|
|
3
|
+
use opentelemetry::sdk::metrics::aggregators::Aggregator;
|
|
4
|
+
use opentelemetry::sdk::metrics::sdk_api::{Descriptor, InstrumentKind};
|
|
3
5
|
use opentelemetry::{
|
|
4
6
|
global,
|
|
5
|
-
metrics::{Counter,
|
|
7
|
+
metrics::{Counter, Histogram, Meter},
|
|
6
8
|
sdk::{
|
|
7
|
-
export::metrics::
|
|
9
|
+
export::metrics::AggregatorSelector,
|
|
8
10
|
metrics::aggregators::{histogram, last_value, sum},
|
|
9
11
|
},
|
|
10
|
-
KeyValue,
|
|
12
|
+
Context, KeyValue,
|
|
11
13
|
};
|
|
12
|
-
use std::{
|
|
14
|
+
use std::{sync::Arc, time::Duration};
|
|
13
15
|
|
|
14
16
|
/// Used to track context associated with metrics, and record/update them
|
|
15
17
|
///
|
|
@@ -17,12 +19,16 @@ use std::{borrow::Cow, sync::Arc, time::Duration};
|
|
|
17
19
|
/// appropriate k/vs have already been set.
|
|
18
20
|
#[derive(Default, Clone, Debug)]
|
|
19
21
|
pub(crate) struct MetricsContext {
|
|
22
|
+
ctx: Context,
|
|
20
23
|
kvs: Arc<Vec<KeyValue>>,
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
impl MetricsContext {
|
|
24
27
|
fn new(kvs: Vec<KeyValue>) -> Self {
|
|
25
|
-
Self {
|
|
28
|
+
Self {
|
|
29
|
+
ctx: Context::current(),
|
|
30
|
+
kvs: Arc::new(kvs),
|
|
31
|
+
}
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
pub(crate) fn top_level(namespace: String) -> Self {
|
|
@@ -38,113 +44,116 @@ impl MetricsContext {
|
|
|
38
44
|
pub(crate) fn with_new_attrs(&self, new_kvs: impl IntoIterator<Item = KeyValue>) -> Self {
|
|
39
45
|
let mut kvs = self.kvs.clone();
|
|
40
46
|
Arc::make_mut(&mut kvs).extend(new_kvs);
|
|
41
|
-
Self {
|
|
47
|
+
Self {
|
|
48
|
+
ctx: Context::current(),
|
|
49
|
+
kvs,
|
|
50
|
+
}
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
/// A workflow task queue poll succeeded
|
|
45
54
|
pub(crate) fn wf_tq_poll_ok(&self) {
|
|
46
|
-
WF_TASK_QUEUE_POLL_SUCCEED_COUNTER.add(1, &self.kvs);
|
|
55
|
+
WF_TASK_QUEUE_POLL_SUCCEED_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/// A workflow task queue poll timed out / had empty response
|
|
50
59
|
pub(crate) fn wf_tq_poll_empty(&self) {
|
|
51
|
-
WF_TASK_QUEUE_POLL_EMPTY_COUNTER.add(1, &self.kvs);
|
|
60
|
+
WF_TASK_QUEUE_POLL_EMPTY_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
/// A workflow task execution failed
|
|
55
64
|
pub(crate) fn wf_task_failed(&self) {
|
|
56
|
-
WF_TASK_EXECUTION_FAILURE_COUNTER.add(1, &self.kvs);
|
|
65
|
+
WF_TASK_EXECUTION_FAILURE_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
/// A workflow completed successfully
|
|
60
69
|
pub(crate) fn wf_completed(&self) {
|
|
61
|
-
WF_COMPLETED_COUNTER.add(1, &self.kvs);
|
|
70
|
+
WF_COMPLETED_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
/// A workflow ended cancelled
|
|
65
74
|
pub(crate) fn wf_canceled(&self) {
|
|
66
|
-
WF_CANCELED_COUNTER.add(1, &self.kvs);
|
|
75
|
+
WF_CANCELED_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
/// A workflow ended failed
|
|
70
79
|
pub(crate) fn wf_failed(&self) {
|
|
71
|
-
WF_FAILED_COUNTER.add(1, &self.kvs);
|
|
80
|
+
WF_FAILED_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
/// A workflow continued as new
|
|
75
84
|
pub(crate) fn wf_continued_as_new(&self) {
|
|
76
|
-
WF_CONT_COUNTER.add(1, &self.kvs);
|
|
85
|
+
WF_CONT_COUNTER.add(&self.ctx, 1, &self.kvs);
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
/// Record workflow total execution time in milliseconds
|
|
80
89
|
pub(crate) fn wf_e2e_latency(&self, dur: Duration) {
|
|
81
|
-
WF_E2E_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
90
|
+
WF_E2E_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
/// Record workflow task schedule to start time in millis
|
|
85
94
|
pub(crate) fn wf_task_sched_to_start_latency(&self, dur: Duration) {
|
|
86
|
-
WF_TASK_SCHED_TO_START_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
95
|
+
WF_TASK_SCHED_TO_START_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
/// Record workflow task execution time in milliseconds
|
|
90
99
|
pub(crate) fn wf_task_latency(&self, dur: Duration) {
|
|
91
|
-
WF_TASK_EXECUTION_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
100
|
+
WF_TASK_EXECUTION_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
/// Record time it takes to catch up on replaying a WFT
|
|
95
104
|
pub(crate) fn wf_task_replay_latency(&self, dur: Duration) {
|
|
96
|
-
WF_TASK_REPLAY_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
105
|
+
WF_TASK_REPLAY_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/// An activity long poll timed out
|
|
100
109
|
pub(crate) fn act_poll_timeout(&self) {
|
|
101
|
-
ACT_POLL_NO_TASK.add(1, &self.kvs);
|
|
110
|
+
ACT_POLL_NO_TASK.add(&self.ctx, 1, &self.kvs);
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
/// An activity execution failed
|
|
105
114
|
pub(crate) fn act_execution_failed(&self) {
|
|
106
|
-
ACT_EXECUTION_FAILED.add(1, &self.kvs);
|
|
115
|
+
ACT_EXECUTION_FAILED.add(&self.ctx, 1, &self.kvs);
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
/// Record activity task schedule to start time in millis
|
|
110
119
|
pub(crate) fn act_sched_to_start_latency(&self, dur: Duration) {
|
|
111
|
-
ACT_SCHED_TO_START_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
120
|
+
ACT_SCHED_TO_START_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
/// Record time it took to complete activity execution, from the time core generated the
|
|
115
124
|
/// activity task, to the time lang responded with a completion (failure or success).
|
|
116
125
|
pub(crate) fn act_execution_latency(&self, dur: Duration) {
|
|
117
|
-
ACT_EXEC_LATENCY.record(dur.as_millis() as u64, &self.kvs);
|
|
126
|
+
ACT_EXEC_LATENCY.record(&self.ctx, dur.as_millis() as u64, &self.kvs);
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
/// A worker was registered
|
|
121
130
|
pub(crate) fn worker_registered(&self) {
|
|
122
|
-
WORKER_REGISTERED.add(1, &self.kvs);
|
|
131
|
+
WORKER_REGISTERED.add(&self.ctx, 1, &self.kvs);
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
/// Record current number of available task slots. Context should have worker type set.
|
|
126
135
|
pub(crate) fn available_task_slots(&self, num: usize) {
|
|
127
|
-
TASK_SLOTS_AVAILABLE.record(num as u64, &self.kvs)
|
|
136
|
+
TASK_SLOTS_AVAILABLE.record(&self.ctx, num as u64, &self.kvs)
|
|
128
137
|
}
|
|
129
138
|
|
|
130
139
|
/// Record current number of pollers. Context should include poller type / task queue tag.
|
|
131
140
|
pub(crate) fn record_num_pollers(&self, num: usize) {
|
|
132
|
-
NUM_POLLERS.record(num as u64, &self.kvs);
|
|
141
|
+
NUM_POLLERS.record(&self.ctx, num as u64, &self.kvs);
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
/// A workflow task found a cached workflow to run against
|
|
136
145
|
pub(crate) fn sticky_cache_hit(&self) {
|
|
137
|
-
STICKY_CACHE_HIT.add(1, &self.kvs);
|
|
146
|
+
STICKY_CACHE_HIT.add(&self.ctx, 1, &self.kvs);
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
/// A workflow task did not find a cached workflow
|
|
141
150
|
pub(crate) fn sticky_cache_miss(&self) {
|
|
142
|
-
STICKY_CACHE_MISS.add(1, &self.kvs);
|
|
151
|
+
STICKY_CACHE_MISS.add(&self.ctx, 1, &self.kvs);
|
|
143
152
|
}
|
|
144
153
|
|
|
145
154
|
/// Record current cache size (in number of wfs, not bytes)
|
|
146
155
|
pub(crate) fn cache_size(&self, size: u64) {
|
|
147
|
-
STICKY_CACHE_SIZE.record(size, &self.kvs);
|
|
156
|
+
STICKY_CACHE_SIZE.record(&self.ctx, size, &self.kvs);
|
|
148
157
|
}
|
|
149
158
|
}
|
|
150
159
|
|
|
@@ -182,8 +191,8 @@ macro_rules! tm {
|
|
|
182
191
|
};
|
|
183
192
|
(vr_u64, $ident:ident, $name:expr) => {
|
|
184
193
|
lazy_static::lazy_static! {
|
|
185
|
-
static ref $ident:
|
|
186
|
-
METRIC_METER.
|
|
194
|
+
static ref $ident: Histogram<u64> = {
|
|
195
|
+
METRIC_METER.u64_histogram(metric_prefix().to_string() + $name).init()
|
|
187
196
|
};
|
|
188
197
|
}
|
|
189
198
|
};
|
|
@@ -214,22 +223,22 @@ pub(crate) fn activity_type(ty: String) -> KeyValue {
|
|
|
214
223
|
pub(crate) fn workflow_type(ty: String) -> KeyValue {
|
|
215
224
|
KeyValue::new(KEY_WF_TYPE, ty)
|
|
216
225
|
}
|
|
217
|
-
pub(crate)
|
|
226
|
+
pub(crate) fn workflow_worker_type() -> KeyValue {
|
|
218
227
|
KeyValue {
|
|
219
228
|
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
220
|
-
value: opentelemetry::Value::String(
|
|
229
|
+
value: opentelemetry::Value::String("WorkflowWorker".into()),
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
|
-
pub(crate)
|
|
232
|
+
pub(crate) fn activity_worker_type() -> KeyValue {
|
|
224
233
|
KeyValue {
|
|
225
234
|
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
226
|
-
value: opentelemetry::Value::String(
|
|
235
|
+
value: opentelemetry::Value::String("ActivityWorker".into()),
|
|
227
236
|
}
|
|
228
237
|
}
|
|
229
|
-
pub(crate)
|
|
238
|
+
pub(crate) fn local_activity_worker_type() -> KeyValue {
|
|
230
239
|
KeyValue {
|
|
231
240
|
key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
|
|
232
|
-
value: opentelemetry::Value::String(
|
|
241
|
+
value: opentelemetry::Value::String("LocalActivityWorker".into()),
|
|
233
242
|
}
|
|
234
243
|
}
|
|
235
244
|
|
|
@@ -338,12 +347,12 @@ pub struct SDKAggSelector;
|
|
|
338
347
|
|
|
339
348
|
impl AggregatorSelector for SDKAggSelector {
|
|
340
349
|
fn aggregator_for(&self, descriptor: &Descriptor) -> Option<Arc<dyn Aggregator + Send + Sync>> {
|
|
341
|
-
//
|
|
342
|
-
if *descriptor.instrument_kind() == InstrumentKind::
|
|
350
|
+
// Gauges are always last value
|
|
351
|
+
if *descriptor.instrument_kind() == InstrumentKind::GaugeObserver {
|
|
343
352
|
return Some(Arc::new(last_value()));
|
|
344
353
|
}
|
|
345
354
|
|
|
346
|
-
if *descriptor.instrument_kind() == InstrumentKind::
|
|
355
|
+
if *descriptor.instrument_kind() == InstrumentKind::Histogram {
|
|
347
356
|
let dname = descriptor
|
|
348
357
|
.name()
|
|
349
358
|
.strip_prefix(metric_prefix())
|
|
@@ -366,7 +375,7 @@ impl AggregatorSelector for SDKAggSelector {
|
|
|
366
375
|
ACT_EXEC_LATENCY_NAME => ACT_EXE_MS_BUCKETS,
|
|
367
376
|
_ => DEFAULT_MS_BUCKETS,
|
|
368
377
|
};
|
|
369
|
-
return Some(Arc::new(histogram(
|
|
378
|
+
return Some(Arc::new(histogram(buckets)));
|
|
370
379
|
}
|
|
371
380
|
|
|
372
381
|
Some(Arc::new(sum()))
|
|
@@ -12,8 +12,12 @@ use once_cell::sync::OnceCell;
|
|
|
12
12
|
use opentelemetry::{
|
|
13
13
|
global,
|
|
14
14
|
metrics::Meter,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
runtime,
|
|
16
|
+
sdk::{
|
|
17
|
+
export::metrics::aggregation::{self, Temporality, TemporalitySelector},
|
|
18
|
+
trace::Config,
|
|
19
|
+
Resource,
|
|
20
|
+
},
|
|
17
21
|
KeyValue,
|
|
18
22
|
};
|
|
19
23
|
use opentelemetry_otlp::WithExportConfig;
|
|
@@ -25,6 +29,7 @@ use std::{
|
|
|
25
29
|
time::Duration,
|
|
26
30
|
};
|
|
27
31
|
use temporal_sdk_core_api::CoreTelemetry;
|
|
32
|
+
use tonic::metadata::MetadataMap;
|
|
28
33
|
use tracing_subscriber::{filter::ParseError, layer::SubscriberExt, EnvFilter};
|
|
29
34
|
use url::Url;
|
|
30
35
|
|
|
@@ -68,7 +73,7 @@ pub enum MetricsExporter {
|
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/// Control where logs go
|
|
71
|
-
#[derive(Debug, Clone)]
|
|
76
|
+
#[derive(Debug, Clone, Copy)]
|
|
72
77
|
pub enum Logger {
|
|
73
78
|
/// Log directly to console.
|
|
74
79
|
Console,
|
|
@@ -100,6 +105,33 @@ pub struct TelemetryOptions {
|
|
|
100
105
|
/// the prefix is consistent with other SDKs.
|
|
101
106
|
#[builder(default)]
|
|
102
107
|
pub no_temporal_prefix_for_metrics: bool,
|
|
108
|
+
|
|
109
|
+
/// Specifies the aggregation temporality for metric export. Defaults to cumulative.
|
|
110
|
+
#[builder(default = "MetricTemporality::Cumulative")]
|
|
111
|
+
pub metric_temporality: MetricTemporality,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Types of aggregation temporality for metric export.
|
|
115
|
+
/// See: <https://github.com/open-telemetry/opentelemetry-specification/blob/ce50e4634efcba8da445cc23523243cb893905cb/specification/metrics/datamodel.md#temporality>
|
|
116
|
+
#[derive(Debug, Clone, Copy)]
|
|
117
|
+
pub enum MetricTemporality {
|
|
118
|
+
/// Successive data points repeat the starting timestamp
|
|
119
|
+
Cumulative,
|
|
120
|
+
/// Successive data points advance the starting timestamp
|
|
121
|
+
Delta,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
impl MetricTemporality {
|
|
125
|
+
fn to_selector(self) -> impl TemporalitySelector + Send + Sync + Clone {
|
|
126
|
+
match self {
|
|
127
|
+
MetricTemporality::Cumulative => {
|
|
128
|
+
aggregation::constant_temporality_selector(Temporality::Cumulative)
|
|
129
|
+
}
|
|
130
|
+
MetricTemporality::Delta => {
|
|
131
|
+
aggregation::constant_temporality_selector(Temporality::Delta)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
103
135
|
}
|
|
104
136
|
|
|
105
137
|
impl TelemetryOptions {
|
|
@@ -122,7 +154,6 @@ impl Default for TelemetryOptions {
|
|
|
122
154
|
/// Things that need to not be dropped while telemetry is ongoing
|
|
123
155
|
#[derive(Default)]
|
|
124
156
|
pub struct GlobalTelemDat {
|
|
125
|
-
metric_push_controller: Option<PushController>,
|
|
126
157
|
core_export_logger: Option<CoreExportLogger>,
|
|
127
158
|
runtime: Option<tokio::runtime::Runtime>,
|
|
128
159
|
prom_srv: Option<PromServer>,
|
|
@@ -201,7 +232,7 @@ pub fn telemetry_init(opts: &TelemetryOptions) -> Result<&'static GlobalTelemDat
|
|
|
201
232
|
.pretty()
|
|
202
233
|
.with_source_location(false);
|
|
203
234
|
let reg = tracing_subscriber::registry()
|
|
204
|
-
.with((
|
|
235
|
+
.with((opts).try_get_env_filter()?)
|
|
205
236
|
.with(
|
|
206
237
|
tracing_subscriber::fmt::layer()
|
|
207
238
|
.with_target(false)
|
|
@@ -220,31 +251,31 @@ pub fn telemetry_init(opts: &TelemetryOptions) -> Result<&'static GlobalTelemDat
|
|
|
220
251
|
if let Some(ref metrics) = opts.metrics {
|
|
221
252
|
match metrics {
|
|
222
253
|
MetricsExporter::Prometheus(addr) => {
|
|
223
|
-
let srv = PromServer::new(*addr)?;
|
|
254
|
+
let srv = PromServer::new(*addr, opts.metric_temporality.to_selector())?;
|
|
224
255
|
globaldat.prom_srv = Some(srv);
|
|
225
256
|
}
|
|
226
257
|
MetricsExporter::Otel(OtelCollectorOptions { url, headers }) => {
|
|
227
258
|
runtime.block_on(async {
|
|
228
259
|
let metrics = opentelemetry_otlp::new_pipeline()
|
|
229
|
-
.metrics(
|
|
230
|
-
|
|
260
|
+
.metrics(
|
|
261
|
+
SDKAggSelector,
|
|
262
|
+
opts.metric_temporality.to_selector(),
|
|
263
|
+
runtime::Tokio,
|
|
264
|
+
)
|
|
231
265
|
.with_period(Duration::from_secs(1))
|
|
232
|
-
.with_resource(
|
|
266
|
+
.with_resource(default_resource())
|
|
233
267
|
.with_exporter(
|
|
234
268
|
// No joke exporter builder literally not cloneable for some insane
|
|
235
269
|
// reason
|
|
236
270
|
opentelemetry_otlp::new_exporter()
|
|
237
271
|
.tonic()
|
|
238
272
|
.with_endpoint(url.to_string())
|
|
239
|
-
.with_metadata(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
),
|
|
243
|
-
),
|
|
273
|
+
.with_metadata(MetadataMap::from_headers(
|
|
274
|
+
headers.try_into()?,
|
|
275
|
+
)),
|
|
244
276
|
)
|
|
245
277
|
.build()?;
|
|
246
|
-
global::set_meter_provider(metrics
|
|
247
|
-
globaldat.metric_push_controller = Some(metrics);
|
|
278
|
+
global::set_meter_provider(metrics);
|
|
248
279
|
Result::<(), anyhow::Error>::Ok(())
|
|
249
280
|
})?;
|
|
250
281
|
}
|
|
@@ -262,14 +293,12 @@ pub fn telemetry_init(opts: &TelemetryOptions) -> Result<&'static GlobalTelemDat
|
|
|
262
293
|
opentelemetry_otlp::new_exporter()
|
|
263
294
|
.tonic()
|
|
264
295
|
.with_endpoint(url.to_string())
|
|
265
|
-
.with_metadata(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
),
|
|
269
|
-
),
|
|
296
|
+
.with_metadata(MetadataMap::from_headers(
|
|
297
|
+
headers.try_into()?,
|
|
298
|
+
)),
|
|
270
299
|
)
|
|
271
300
|
.with_trace_config(tracer_cfg)
|
|
272
|
-
.install_batch(
|
|
301
|
+
.install_batch(runtime::Tokio)?;
|
|
273
302
|
|
|
274
303
|
let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
|
275
304
|
|
|
@@ -334,6 +363,7 @@ pub(crate) fn test_telem_console() {
|
|
|
334
363
|
tracing: None,
|
|
335
364
|
metrics: None,
|
|
336
365
|
no_temporal_prefix_for_metrics: false,
|
|
366
|
+
metric_temporality: MetricTemporality::Cumulative,
|
|
337
367
|
})
|
|
338
368
|
.unwrap();
|
|
339
369
|
}
|
|
@@ -350,6 +380,7 @@ pub(crate) fn test_telem_collector() {
|
|
|
350
380
|
})),
|
|
351
381
|
metrics: None,
|
|
352
382
|
no_temporal_prefix_for_metrics: false,
|
|
383
|
+
metric_temporality: MetricTemporality::Cumulative,
|
|
353
384
|
})
|
|
354
385
|
.unwrap();
|
|
355
386
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
use crate::telemetry::{
|
|
2
|
-
default_resource,
|
|
3
|
-
metrics::{SDKAggSelector, DEFAULT_MS_BUCKETS},
|
|
4
|
-
};
|
|
1
|
+
use crate::telemetry::{default_resource, metrics::SDKAggSelector};
|
|
5
2
|
use hyper::{
|
|
6
3
|
header::CONTENT_TYPE,
|
|
7
4
|
service::{make_service_fn, service_fn},
|
|
8
5
|
Body, Method, Request, Response, Server,
|
|
9
6
|
};
|
|
10
|
-
use opentelemetry::
|
|
7
|
+
use opentelemetry::{
|
|
8
|
+
metrics::MetricsError,
|
|
9
|
+
sdk::{
|
|
10
|
+
export::metrics::aggregation::TemporalitySelector,
|
|
11
|
+
metrics::{controllers, processors},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
11
14
|
use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
|
|
12
15
|
use prometheus::{Encoder, TextEncoder};
|
|
13
16
|
use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
|
@@ -19,14 +22,15 @@ pub(super) struct PromServer {
|
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
impl PromServer {
|
|
22
|
-
pub fn new(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
pub fn new(
|
|
26
|
+
addr: SocketAddr,
|
|
27
|
+
temporality: impl TemporalitySelector + Send + Sync + 'static,
|
|
28
|
+
) -> Result<Self, MetricsError> {
|
|
29
|
+
let controller =
|
|
30
|
+
controllers::basic(processors::factory(SDKAggSelector, temporality).with_memory(true))
|
|
31
|
+
.with_resource(default_resource())
|
|
32
|
+
.build();
|
|
33
|
+
let exporter = ExporterBuilder::new(controller).try_init()?;
|
|
30
34
|
Ok(Self {
|
|
31
35
|
exporter: Arc::new(exporter),
|
|
32
36
|
addr,
|
|
@@ -17,6 +17,7 @@ pub(crate) fn mock_manual_workflow_client() -> MockManualWorkerClient {
|
|
|
17
17
|
// https://github.com/asomers/mockall/issues/189 to be fixed for it to go away.
|
|
18
18
|
mockall::mock! {
|
|
19
19
|
pub ManualWorkerClient {}
|
|
20
|
+
#[allow(unused)]
|
|
20
21
|
impl WorkerClient for ManualWorkerClient {
|
|
21
22
|
fn poll_workflow_task<'a, 'b>(&'a self, task_queue: String, is_sticky: bool)
|
|
22
23
|
-> impl Future<Output = Result<PollWorkflowTaskQueueResponse>> + Send + 'b
|
|
@@ -78,6 +78,7 @@ use tokio_util::sync::CancellationToken;
|
|
|
78
78
|
use tracing::Span;
|
|
79
79
|
|
|
80
80
|
pub(crate) const LEGACY_QUERY_ID: &str = "legacy_query";
|
|
81
|
+
const MAX_EAGER_ACTIVITY_RESERVATIONS_PER_WORKFLOW_TASK: usize = 3;
|
|
81
82
|
|
|
82
83
|
type Result<T, E = WFMachinesError> = result::Result<T, E>;
|
|
83
84
|
type BoxedActivationStream = BoxStream<'static, Result<ActivationOrAuto, PollWfError>>;
|
|
@@ -472,7 +473,9 @@ impl Workflows {
|
|
|
472
473
|
.as_ref()
|
|
473
474
|
.map(|q| q.name == self.task_queue)
|
|
474
475
|
.unwrap_or_default();
|
|
475
|
-
if same_task_queue
|
|
476
|
+
if same_task_queue
|
|
477
|
+
&& reserved.len() < MAX_EAGER_ACTIVITY_RESERVATIONS_PER_WORKFLOW_TASK
|
|
478
|
+
{
|
|
476
479
|
if let Some(p) = at_handle.reserve_slot() {
|
|
477
480
|
reserved.push(p);
|
|
478
481
|
} else {
|
|
@@ -20,6 +20,7 @@ use temporal_client::{
|
|
|
20
20
|
};
|
|
21
21
|
use temporal_sdk::{interceptors::WorkerInterceptor, IntoActivityFunc, Worker, WorkflowFunction};
|
|
22
22
|
use temporal_sdk_core::{
|
|
23
|
+
ephemeral_server::{EphemeralExe, EphemeralExeVersion},
|
|
23
24
|
init_replay_worker, init_worker, telemetry_init, ClientOptions, ClientOptionsBuilder, Logger,
|
|
24
25
|
MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
|
|
25
26
|
TraceExporter, WorkerConfig, WorkerConfigBuilder,
|
|
@@ -40,11 +41,17 @@ use url::Url;
|
|
|
40
41
|
|
|
41
42
|
pub const NAMESPACE: &str = "default";
|
|
42
43
|
pub const TEST_Q: &str = "q";
|
|
44
|
+
/// The env var used to specify where the integ tests should point
|
|
45
|
+
pub const INTEG_SERVER_TARGET_ENV_VAR: &str = "TEMPORAL_SERVICE_ADDRESS";
|
|
46
|
+
/// This env var is set (to any value) if temporalite is in use
|
|
47
|
+
pub const INTEG_TEMPORALITE_USED_ENV_VAR: &str = "INTEG_TEMPORALITE_ON";
|
|
48
|
+
/// This env var is set (to any value) if the test server is in use
|
|
49
|
+
pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
|
|
50
|
+
|
|
43
51
|
/// If set, turn export traces and metrics to the OTel collector at the given URL
|
|
44
52
|
const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
|
|
45
53
|
/// If set, enable direct scraping of prom metrics on the specified port
|
|
46
54
|
const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
|
|
47
|
-
|
|
48
55
|
/// Create a worker instance which will use the provided test name to base the task queue and wf id
|
|
49
56
|
/// upon. Returns the instance and the task queue name (which is also the workflow id).
|
|
50
57
|
pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
|
|
@@ -433,8 +440,10 @@ impl WorkerInterceptor for TestWorkerCompletionIceptor {
|
|
|
433
440
|
}
|
|
434
441
|
}
|
|
435
442
|
|
|
443
|
+
/// Returns the client options used to connect to the server used for integration tests.
|
|
436
444
|
pub fn get_integ_server_options() -> ClientOptions {
|
|
437
|
-
|
|
445
|
+
telemetry_init(&get_integ_telem_options()).expect("Telemetry inits cleanly");
|
|
446
|
+
let temporal_server_address = match env::var(INTEG_SERVER_TARGET_ENV_VAR) {
|
|
438
447
|
Ok(addr) => addr,
|
|
439
448
|
Err(_) => "http://localhost:7233".to_owned(),
|
|
440
449
|
};
|
|
@@ -473,6 +482,16 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
473
482
|
.unwrap()
|
|
474
483
|
}
|
|
475
484
|
|
|
485
|
+
pub fn default_cached_download() -> EphemeralExe {
|
|
486
|
+
EphemeralExe::CachedDownload {
|
|
487
|
+
version: EphemeralExeVersion::Default {
|
|
488
|
+
sdk_name: "sdk-rust".to_string(),
|
|
489
|
+
sdk_version: "0.1.0".to_string(),
|
|
490
|
+
},
|
|
491
|
+
dest_dir: None,
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
476
495
|
pub fn schedule_activity_cmd(
|
|
477
496
|
seq: u32,
|
|
478
497
|
task_q: &str,
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
2
|
-
use temporal_client::{TestService, WorkflowService};
|
|
3
|
-
use temporal_sdk_core::{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
TestServerConfigBuilder,
|
|
7
|
-
},
|
|
8
|
-
ClientOptions, ClientOptionsBuilder,
|
|
2
|
+
use temporal_client::{ClientOptionsBuilder, TestService, WorkflowService};
|
|
3
|
+
use temporal_sdk_core::ephemeral_server::{
|
|
4
|
+
EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporaliteConfigBuilder,
|
|
5
|
+
TestServerConfigBuilder,
|
|
9
6
|
};
|
|
10
7
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
|
|
11
|
-
use temporal_sdk_core_test_utils::NAMESPACE;
|
|
8
|
+
use temporal_sdk_core_test_utils::{default_cached_download, NAMESPACE};
|
|
12
9
|
use url::Url;
|
|
13
10
|
|
|
14
11
|
#[tokio::test]
|
|
@@ -17,8 +14,9 @@ async fn temporalite_default() {
|
|
|
17
14
|
.exe(default_cached_download())
|
|
18
15
|
.build()
|
|
19
16
|
.unwrap();
|
|
20
|
-
let server = config.start_server().await.unwrap();
|
|
17
|
+
let mut server = config.start_server().await.unwrap();
|
|
21
18
|
assert_ephemeral_server(&server).await;
|
|
19
|
+
server.shutdown().await.unwrap();
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
#[tokio::test]
|
|
@@ -27,8 +25,9 @@ async fn temporalite_fixed() {
|
|
|
27
25
|
.exe(fixed_cached_download("v0.1.1"))
|
|
28
26
|
.build()
|
|
29
27
|
.unwrap();
|
|
30
|
-
let server = config.start_server().await.unwrap();
|
|
28
|
+
let mut server = config.start_server().await.unwrap();
|
|
31
29
|
assert_ephemeral_server(&server).await;
|
|
30
|
+
server.shutdown().await.unwrap();
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
#[tokio::test]
|
|
@@ -54,8 +53,9 @@ async fn test_server_default() {
|
|
|
54
53
|
.exe(default_cached_download())
|
|
55
54
|
.build()
|
|
56
55
|
.unwrap();
|
|
57
|
-
let server = config.start_server().await.unwrap();
|
|
56
|
+
let mut server = config.start_server().await.unwrap();
|
|
58
57
|
assert_ephemeral_server(&server).await;
|
|
58
|
+
server.shutdown().await.unwrap();
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
#[tokio::test]
|
|
@@ -64,8 +64,9 @@ async fn test_server_fixed() {
|
|
|
64
64
|
.exe(fixed_cached_download("v1.16.0"))
|
|
65
65
|
.build()
|
|
66
66
|
.unwrap();
|
|
67
|
-
let server = config.start_server().await.unwrap();
|
|
67
|
+
let mut server = config.start_server().await.unwrap();
|
|
68
68
|
assert_ephemeral_server(&server).await;
|
|
69
|
+
server.shutdown().await.unwrap();
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
#[tokio::test]
|
|
@@ -85,9 +86,22 @@ async fn test_server_shutdown_port_reuse() {
|
|
|
85
86
|
server.shutdown().await.unwrap();
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
fn fixed_cached_download(version: &str) -> EphemeralExe {
|
|
90
|
+
EphemeralExe::CachedDownload {
|
|
91
|
+
version: EphemeralExeVersion::Fixed(version.to_string()),
|
|
92
|
+
dest_dir: None,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
async fn assert_ephemeral_server(server: &EphemeralServer) {
|
|
89
97
|
// Connect and describe namespace
|
|
90
|
-
let mut client =
|
|
98
|
+
let mut client = ClientOptionsBuilder::default()
|
|
99
|
+
.identity("integ_tester".to_string())
|
|
100
|
+
.target_url(Url::try_from(&*format!("http://{}", server.target)).unwrap())
|
|
101
|
+
.client_name("temporal-core".to_string())
|
|
102
|
+
.client_version("0.1.0".to_string())
|
|
103
|
+
.build()
|
|
104
|
+
.unwrap()
|
|
91
105
|
.connect_no_namespace(None, None)
|
|
92
106
|
.await
|
|
93
107
|
.unwrap();
|
|
@@ -112,30 +126,3 @@ async fn assert_ephemeral_server(server: &EphemeralServer) {
|
|
|
112
126
|
assert!(curr_seconds - 300 < resp_seconds && curr_seconds + 300 > resp_seconds);
|
|
113
127
|
}
|
|
114
128
|
}
|
|
115
|
-
|
|
116
|
-
fn default_cached_download() -> EphemeralExe {
|
|
117
|
-
EphemeralExe::CachedDownload {
|
|
118
|
-
version: EphemeralExeVersion::Default {
|
|
119
|
-
sdk_name: "sdk-rust".to_string(),
|
|
120
|
-
sdk_version: "0.1.0".to_string(),
|
|
121
|
-
},
|
|
122
|
-
dest_dir: None,
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
fn fixed_cached_download(version: &str) -> EphemeralExe {
|
|
127
|
-
EphemeralExe::CachedDownload {
|
|
128
|
-
version: EphemeralExeVersion::Fixed(version.to_string()),
|
|
129
|
-
dest_dir: None,
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
fn client_options(target: &str) -> ClientOptions {
|
|
134
|
-
return ClientOptionsBuilder::default()
|
|
135
|
-
.identity("integ_tester".to_string())
|
|
136
|
-
.target_url(Url::try_from(&*format!("http://{}", target)).unwrap())
|
|
137
|
-
.client_name("temporal-core".to_string())
|
|
138
|
-
.client_version("0.1.0".to_string())
|
|
139
|
-
.build()
|
|
140
|
-
.unwrap();
|
|
141
|
-
}
|
|
@@ -133,6 +133,7 @@ async fn can_paginate_long_history() {
|
|
|
133
133
|
worker.run_until_done().await.unwrap();
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
// TODO: Takes ages now, fix somehow
|
|
136
137
|
#[tokio::test]
|
|
137
138
|
async fn poll_of_nonexistent_namespace_is_fatal() {
|
|
138
139
|
let mut starter = CoreWfStarter::new("whatever_yo");
|