@temporalio/core-bridge 1.12.0 → 1.12.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.
Files changed (116) hide show
  1. package/Cargo.lock +64 -119
  2. package/Cargo.toml +1 -1
  3. package/index.js +3 -2
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.cargo/config.toml +1 -2
  11. package/sdk-core/.github/workflows/per-pr.yml +2 -0
  12. package/sdk-core/AGENTS.md +7 -0
  13. package/sdk-core/Cargo.toml +9 -5
  14. package/sdk-core/README.md +6 -5
  15. package/sdk-core/client/Cargo.toml +3 -2
  16. package/sdk-core/client/src/lib.rs +17 -8
  17. package/sdk-core/client/src/metrics.rs +57 -23
  18. package/sdk-core/client/src/raw.rs +33 -15
  19. package/sdk-core/core/Cargo.toml +11 -9
  20. package/sdk-core/core/benches/workflow_replay.rs +114 -15
  21. package/sdk-core/core/src/core_tests/activity_tasks.rs +18 -18
  22. package/sdk-core/core/src/core_tests/child_workflows.rs +4 -4
  23. package/sdk-core/core/src/core_tests/determinism.rs +6 -6
  24. package/sdk-core/core/src/core_tests/local_activities.rs +20 -20
  25. package/sdk-core/core/src/core_tests/mod.rs +40 -5
  26. package/sdk-core/core/src/core_tests/queries.rs +25 -16
  27. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -3
  28. package/sdk-core/core/src/core_tests/updates.rs +3 -3
  29. package/sdk-core/core/src/core_tests/workers.rs +9 -7
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +40 -42
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +1 -19
  32. package/sdk-core/core/src/lib.rs +10 -1
  33. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  34. package/sdk-core/core/src/replay/mod.rs +3 -3
  35. package/sdk-core/core/src/telemetry/metrics.rs +306 -152
  36. package/sdk-core/core/src/telemetry/mod.rs +11 -4
  37. package/sdk-core/core/src/telemetry/otel.rs +134 -131
  38. package/sdk-core/core/src/telemetry/prometheus_meter.rs +885 -0
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +48 -28
  40. package/sdk-core/core/src/test_help/mod.rs +27 -12
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +7 -7
  42. package/sdk-core/core/src/worker/activities.rs +4 -4
  43. package/sdk-core/core/src/worker/client/mocks.rs +10 -3
  44. package/sdk-core/core/src/worker/client.rs +68 -5
  45. package/sdk-core/core/src/worker/heartbeat.rs +229 -0
  46. package/sdk-core/core/src/worker/mod.rs +35 -14
  47. package/sdk-core/core/src/worker/tuner/resource_based.rs +4 -4
  48. package/sdk-core/core/src/worker/workflow/history_update.rs +71 -19
  49. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -2
  50. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -1
  51. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +31 -48
  52. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -2
  53. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +3 -3
  54. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +4 -1
  55. package/sdk-core/core/src/worker/workflow/managed_run.rs +1 -1
  56. package/sdk-core/core/src/worker/workflow/mod.rs +15 -15
  57. package/sdk-core/core-api/Cargo.toml +2 -2
  58. package/sdk-core/core-api/src/envconfig.rs +204 -99
  59. package/sdk-core/core-api/src/lib.rs +9 -0
  60. package/sdk-core/core-api/src/telemetry/metrics.rs +548 -100
  61. package/sdk-core/core-api/src/worker.rs +11 -5
  62. package/sdk-core/core-c-bridge/Cargo.toml +49 -0
  63. package/sdk-core/core-c-bridge/build.rs +26 -0
  64. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +817 -0
  65. package/sdk-core/core-c-bridge/src/client.rs +679 -0
  66. package/sdk-core/core-c-bridge/src/lib.rs +245 -0
  67. package/sdk-core/core-c-bridge/src/metric.rs +682 -0
  68. package/sdk-core/core-c-bridge/src/random.rs +61 -0
  69. package/sdk-core/core-c-bridge/src/runtime.rs +445 -0
  70. package/sdk-core/core-c-bridge/src/testing.rs +282 -0
  71. package/sdk-core/core-c-bridge/src/tests/context.rs +644 -0
  72. package/sdk-core/core-c-bridge/src/tests/mod.rs +178 -0
  73. package/sdk-core/core-c-bridge/src/tests/utils.rs +108 -0
  74. package/sdk-core/core-c-bridge/src/worker.rs +1069 -0
  75. package/sdk-core/etc/deps.svg +64 -64
  76. package/sdk-core/sdk/src/activity_context.rs +6 -4
  77. package/sdk-core/sdk/src/lib.rs +49 -27
  78. package/sdk-core/sdk/src/workflow_future.rs +18 -25
  79. package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +4 -0
  80. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +0 -2
  81. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +630 -83
  82. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +632 -78
  83. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +4 -4
  84. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +6 -4
  85. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
  86. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +32 -2
  87. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +10 -1
  88. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +26 -0
  89. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  90. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
  91. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  92. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +47 -31
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +4 -4
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +7 -1
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/worker/v1/message.proto +134 -0
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +14 -11
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +148 -37
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +21 -0
  99. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -4
  100. package/sdk-core/sdk-core-protos/src/history_builder.rs +9 -5
  101. package/sdk-core/sdk-core-protos/src/lib.rs +96 -6
  102. package/sdk-core/test-utils/src/lib.rs +11 -3
  103. package/sdk-core/tests/cloud_tests.rs +3 -3
  104. package/sdk-core/tests/heavy_tests.rs +11 -3
  105. package/sdk-core/tests/integ_tests/client_tests.rs +12 -13
  106. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +1 -1
  107. package/sdk-core/tests/integ_tests/metrics_tests.rs +188 -83
  108. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
  109. package/sdk-core/tests/integ_tests/queries_tests.rs +56 -40
  110. package/sdk-core/tests/integ_tests/update_tests.rs +2 -7
  111. package/sdk-core/tests/integ_tests/worker_tests.rs +3 -4
  112. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +3 -7
  113. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +3 -5
  114. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +24 -17
  115. package/src/client.rs +6 -0
  116. package/src/metrics.rs +6 -6
@@ -1,4 +1,4 @@
1
- use crate::{AttachMetricLabels, CallType};
1
+ use crate::{AttachMetricLabels, CallType, dbg_panic};
2
2
  use futures_util::{FutureExt, future::BoxFuture};
3
3
  use std::{
4
4
  sync::Arc,
@@ -6,10 +6,10 @@ use std::{
6
6
  time::{Duration, Instant},
7
7
  };
8
8
  use temporal_sdk_core_api::telemetry::metrics::{
9
- CoreMeter, Counter, HistogramDuration, MetricAttributes, MetricKeyValue, MetricParameters,
10
- TemporalMeter,
9
+ CoreMeter, Counter, CounterBase, HistogramDuration, HistogramDurationBase, MetricAttributable,
10
+ MetricAttributes, MetricKeyValue, MetricParameters, TemporalMeter,
11
11
  };
12
- use tonic::{Code, body::BoxBody, transport::Channel};
12
+ use tonic::{Code, body::Body, transport::Channel};
13
13
  use tower::Service;
14
14
 
15
15
  /// The string name (which may be prefixed) for this metric
@@ -26,22 +26,24 @@ pub(crate) struct MetricsContext {
26
26
  meter: Arc<dyn CoreMeter>,
27
27
  kvs: MetricAttributes,
28
28
  poll_is_long: bool,
29
+ instruments: Instruments,
30
+ }
31
+ #[derive(Clone)]
32
+ struct Instruments {
33
+ svc_request: Counter,
34
+ svc_request_failed: Counter,
35
+ long_svc_request: Counter,
36
+ long_svc_request_failed: Counter,
29
37
 
30
- svc_request: Arc<dyn Counter>,
31
- svc_request_failed: Arc<dyn Counter>,
32
- long_svc_request: Arc<dyn Counter>,
33
- long_svc_request_failed: Arc<dyn Counter>,
34
-
35
- svc_request_latency: Arc<dyn HistogramDuration>,
36
- long_svc_request_latency: Arc<dyn HistogramDuration>,
38
+ svc_request_latency: HistogramDuration,
39
+ long_svc_request_latency: HistogramDuration,
37
40
  }
38
41
 
39
42
  impl MetricsContext {
40
43
  pub(crate) fn new(tm: TemporalMeter) -> Self {
41
44
  let meter = tm.inner;
42
- Self {
43
- kvs: meter.new_attributes(tm.default_attribs),
44
- poll_is_long: false,
45
+ let kvs = meter.new_attributes(tm.default_attribs);
46
+ let instruments = Instruments {
45
47
  svc_request: meter.counter(MetricParameters {
46
48
  name: "request".into(),
47
49
  description: "Count of client request successes by rpc name".into(),
@@ -72,6 +74,11 @@ impl MetricsContext {
72
74
  unit: "duration".into(),
73
75
  description: "Histogram of client long-poll request latencies".into(),
74
76
  }),
77
+ };
78
+ Self {
79
+ kvs,
80
+ poll_is_long: false,
81
+ instruments,
75
82
  meter,
76
83
  }
77
84
  }
@@ -81,6 +88,33 @@ impl MetricsContext {
81
88
  self.kvs = self
82
89
  .meter
83
90
  .extend_attributes(self.kvs.clone(), new_kvs.into());
91
+
92
+ let _ = self
93
+ .instruments
94
+ .svc_request
95
+ .with_attributes(&self.kvs)
96
+ .and_then(|v| {
97
+ self.instruments.svc_request = v;
98
+ self.instruments.long_svc_request.with_attributes(&self.kvs)
99
+ })
100
+ .and_then(|v| {
101
+ self.instruments.long_svc_request = v;
102
+ self.instruments
103
+ .svc_request_latency
104
+ .with_attributes(&self.kvs)
105
+ })
106
+ .and_then(|v| {
107
+ self.instruments.svc_request_latency = v;
108
+ self.instruments
109
+ .long_svc_request_latency
110
+ .with_attributes(&self.kvs)
111
+ })
112
+ .map(|v| {
113
+ self.instruments.long_svc_request_latency = v;
114
+ })
115
+ .inspect_err(|e| {
116
+ dbg_panic!("Failed to extend client metrics attributes: {:?}", e);
117
+ });
84
118
  }
85
119
 
86
120
  pub(crate) fn set_is_long_poll(&mut self) {
@@ -90,9 +124,9 @@ impl MetricsContext {
90
124
  /// A request to the temporal service was made
91
125
  pub(crate) fn svc_request(&self) {
92
126
  if self.poll_is_long {
93
- self.long_svc_request.add(1, &self.kvs);
127
+ self.instruments.long_svc_request.adds(1);
94
128
  } else {
95
- self.svc_request.add(1, &self.kvs);
129
+ self.instruments.svc_request.adds(1);
96
130
  }
97
131
  }
98
132
 
@@ -108,18 +142,18 @@ impl MetricsContext {
108
142
  &self.kvs
109
143
  };
110
144
  if self.poll_is_long {
111
- self.long_svc_request_failed.add(1, kvs);
145
+ self.instruments.long_svc_request_failed.add(1, kvs);
112
146
  } else {
113
- self.svc_request_failed.add(1, kvs);
147
+ self.instruments.svc_request_failed.add(1, kvs);
114
148
  }
115
149
  }
116
150
 
117
151
  /// Record service request latency
118
152
  pub(crate) fn record_svc_req_latency(&self, dur: Duration) {
119
153
  if self.poll_is_long {
120
- self.long_svc_request_latency.record(dur, &self.kvs);
154
+ self.instruments.long_svc_request_latency.records(dur);
121
155
  } else {
122
- self.svc_request_latency.record(dur, &self.kvs);
156
+ self.instruments.svc_request_latency.records(dur);
123
157
  }
124
158
  }
125
159
  }
@@ -177,8 +211,8 @@ pub struct GrpcMetricSvc {
177
211
  pub(crate) disable_errcode_label: bool,
178
212
  }
179
213
 
180
- impl Service<http::Request<BoxBody>> for GrpcMetricSvc {
181
- type Response = http::Response<BoxBody>;
214
+ impl Service<http::Request<Body>> for GrpcMetricSvc {
215
+ type Response = http::Response<Body>;
182
216
  type Error = tonic::transport::Error;
183
217
  type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
184
218
 
@@ -186,7 +220,7 @@ impl Service<http::Request<BoxBody>> for GrpcMetricSvc {
186
220
  self.inner.poll_ready(cx).map_err(Into::into)
187
221
  }
188
222
 
189
- fn call(&mut self, mut req: http::Request<BoxBody>) -> Self::Future {
223
+ fn call(&mut self, mut req: http::Request<Body>) -> Self::Future {
190
224
  let metrics = self
191
225
  .metrics
192
226
  .clone()
@@ -24,7 +24,7 @@ use temporal_sdk_core_protos::{
24
24
  };
25
25
  use tonic::{
26
26
  Request, Response, Status,
27
- body::BoxBody,
27
+ body::Body,
28
28
  client::GrpcService,
29
29
  metadata::{AsciiMetadataValue, KeyAndValueRef},
30
30
  };
@@ -166,7 +166,7 @@ where
166
166
  impl<T> RawClientLike for TemporalServiceClient<T>
167
167
  where
168
168
  T: Send + Sync + Clone + 'static,
169
- T: GrpcService<BoxBody> + Send + Clone + 'static,
169
+ T: GrpcService<Body> + Send + Clone + 'static,
170
170
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
171
171
  T::Error: Into<tonic::codegen::StdError>,
172
172
  <T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
@@ -221,7 +221,7 @@ where
221
221
  impl<T> RawClientLike for ConfiguredClient<TemporalServiceClient<T>>
222
222
  where
223
223
  T: Send + Sync + Clone + 'static,
224
- T: GrpcService<BoxBody> + Send + Clone + 'static,
224
+ T: GrpcService<Body> + Send + Clone + 'static,
225
225
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
226
226
  T::Error: Into<tonic::codegen::StdError>,
227
227
  <T::ResponseBody as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
@@ -373,7 +373,7 @@ pub(super) struct IsUserLongPoll;
373
373
  impl<RC, T> WorkflowService for RC
374
374
  where
375
375
  RC: RawClientLike<SvcType = T>,
376
- T: GrpcService<BoxBody> + Send + Clone + 'static,
376
+ T: GrpcService<Body> + Send + Clone + 'static,
377
377
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
378
378
  T::Error: Into<tonic::codegen::StdError>,
379
379
  T::Future: Send,
@@ -383,7 +383,7 @@ where
383
383
  impl<RC, T> OperatorService for RC
384
384
  where
385
385
  RC: RawClientLike<SvcType = T>,
386
- T: GrpcService<BoxBody> + Send + Clone + 'static,
386
+ T: GrpcService<Body> + Send + Clone + 'static,
387
387
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
388
388
  T::Error: Into<tonic::codegen::StdError>,
389
389
  T::Future: Send,
@@ -393,7 +393,7 @@ where
393
393
  impl<RC, T> CloudService for RC
394
394
  where
395
395
  RC: RawClientLike<SvcType = T>,
396
- T: GrpcService<BoxBody> + Send + Clone + 'static,
396
+ T: GrpcService<Body> + Send + Clone + 'static,
397
397
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
398
398
  T::Error: Into<tonic::codegen::StdError>,
399
399
  T::Future: Send,
@@ -403,7 +403,7 @@ where
403
403
  impl<RC, T> TestService for RC
404
404
  where
405
405
  RC: RawClientLike<SvcType = T>,
406
- T: GrpcService<BoxBody> + Send + Clone + 'static,
406
+ T: GrpcService<Body> + Send + Clone + 'static,
407
407
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
408
408
  T::Error: Into<tonic::codegen::StdError>,
409
409
  T::Future: Send,
@@ -413,7 +413,7 @@ where
413
413
  impl<RC, T> HealthService for RC
414
414
  where
415
415
  RC: RawClientLike<SvcType = T>,
416
- T: GrpcService<BoxBody> + Send + Clone + 'static,
416
+ T: GrpcService<Body> + Send + Clone + 'static,
417
417
  T::ResponseBody: tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
418
418
  T::Error: Into<tonic::codegen::StdError>,
419
419
  T::Future: Send,
@@ -437,7 +437,7 @@ macro_rules! proxy {
437
437
  fn $method(
438
438
  &mut self,
439
439
  request: impl tonic::IntoRequest<$req>,
440
- ) -> BoxFuture<Result<tonic::Response<$resp>, tonic::Status>> {
440
+ ) -> BoxFuture<'_, Result<tonic::Response<$resp>, tonic::Status>> {
441
441
  #[allow(unused_mut)]
442
442
  let mut as_req = request.into_request();
443
443
  $( type_closure_arg(&mut as_req, $closure); )*
@@ -455,7 +455,7 @@ macro_rules! proxy {
455
455
  fn $method(
456
456
  &mut self,
457
457
  request: impl tonic::IntoRequest<$req>,
458
- ) -> BoxFuture<Result<tonic::Response<$resp>, tonic::Status>> {
458
+ ) -> BoxFuture<'_, Result<tonic::Response<$resp>, tonic::Status>> {
459
459
  #[allow(unused_mut)]
460
460
  let mut as_req = request.into_request();
461
461
  type_closure_arg(&mut as_req, $closure_request);
@@ -483,13 +483,13 @@ macro_rules! proxier {
483
483
  pub trait $trait_name: RawClientLike
484
484
  where
485
485
  // Yo this is wild
486
- <Self as RawClientLike>::SvcType: GrpcService<BoxBody> + Send + Clone + 'static,
487
- <<Self as RawClientLike>::SvcType as GrpcService<BoxBody>>::ResponseBody:
486
+ <Self as RawClientLike>::SvcType: GrpcService<Body> + Send + Clone + 'static,
487
+ <<Self as RawClientLike>::SvcType as GrpcService<Body>>::ResponseBody:
488
488
  tonic::codegen::Body<Data = tonic::codegen::Bytes> + Send + 'static,
489
- <<Self as RawClientLike>::SvcType as GrpcService<BoxBody>>::Error:
489
+ <<Self as RawClientLike>::SvcType as GrpcService<Body>>::Error:
490
490
  Into<tonic::codegen::StdError>,
491
- <<Self as RawClientLike>::SvcType as GrpcService<BoxBody>>::Future: Send,
492
- <<<Self as RawClientLike>::SvcType as GrpcService<BoxBody>>::ResponseBody
491
+ <<Self as RawClientLike>::SvcType as GrpcService<Body>>::Future: Send,
492
+ <<<Self as RawClientLike>::SvcType as GrpcService<Body>>::ResponseBody
493
493
  as tonic::codegen::Body>::Error: Into<tonic::codegen::StdError> + Send,
494
494
  {
495
495
  $(
@@ -1336,6 +1336,24 @@ proxier! {
1336
1336
  r.extensions_mut().insert(labels);
1337
1337
  }
1338
1338
  );
1339
+ (
1340
+ list_workers,
1341
+ ListWorkersRequest,
1342
+ ListWorkersResponse,
1343
+ |r| {
1344
+ let labels = namespaced_request!(r);
1345
+ r.extensions_mut().insert(labels);
1346
+ }
1347
+ );
1348
+ (
1349
+ record_worker_heartbeat,
1350
+ RecordWorkerHeartbeatRequest,
1351
+ RecordWorkerHeartbeatResponse,
1352
+ |r| {
1353
+ let labels = namespaced_request!(r);
1354
+ r.extensions_mut().insert(labels);
1355
+ }
1356
+ );
1339
1357
  }
1340
1358
 
1341
1359
  proxier! {
@@ -13,9 +13,10 @@ categories = ["development-tools"]
13
13
  [lib]
14
14
 
15
15
  [features]
16
- default = ["otel"]
17
- otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp",
18
- "dep:opentelemetry-prometheus", "dep:hyper", "dep:hyper-util", "dep:http-body-util"]
16
+ default = ["otel", "prom"]
17
+ otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp", "dep:hyper",
18
+ "dep:hyper-util", "dep:http-body-util"]
19
+ prom = ["dep:prometheus"]
19
20
  tokio-console = ["console-subscriber"]
20
21
  ephemeral-server = ["dep:flate2", "dep:reqwest", "dep:tar", "dep:zip"]
21
22
  debug-plugin = ["dep:reqwest"]
@@ -35,6 +36,7 @@ enum-iterator = "2"
35
36
  flate2 = { version = "1.0", optional = true }
36
37
  futures-util = { version = "0.3", default-features = false }
37
38
  futures-channel = { version = "0.3", default-features = false, features = ["std"] }
39
+ gethostname = "1.0.2"
38
40
  governor = "0.8"
39
41
  http-body-util = { version = "0.1", optional = true }
40
42
  hyper = { version = "1.2", optional = true }
@@ -43,13 +45,12 @@ itertools = "0.14"
43
45
  lru = "0.13"
44
46
  mockall = "0.13"
45
47
  opentelemetry = { workspace = true, features = ["metrics"], optional = true }
46
- opentelemetry_sdk = { version = "0.29", features = ["rt-tokio", "metrics", "spec_unstable_metrics_views"], optional = true }
47
- opentelemetry-otlp = { version = "0.29", features = ["tokio", "metrics", "tls", "http-proto", "grpc-tonic"], optional = true }
48
- opentelemetry-prometheus = { version = "0.29", optional = true }
48
+ opentelemetry_sdk = { version = "0.30", features = ["rt-tokio", "metrics", "spec_unstable_metrics_views"], optional = true }
49
+ opentelemetry-otlp = { version = "0.30", features = ["tokio", "metrics", "tls", "http-proto", "grpc-tonic"], optional = true }
49
50
  parking_lot = { version = "0.12", features = ["send_guard"] }
50
51
  pid = "4.0"
51
52
  pin-project = "1.0"
52
- prometheus = "0.14"
53
+ prometheus = { version = "0.14", optional = true }
53
54
  prost = { workspace = true }
54
55
  prost-types = { version = "0.6", package = "prost-wkt-types" }
55
56
  rand = "0.9"
@@ -65,7 +66,7 @@ thiserror = { workspace = true }
65
66
  tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
66
67
  tokio-util = { version = "0.7", features = ["io", "io-util"] }
67
68
  tokio-stream = "0.1"
68
- tonic = { workspace = true, features = ["tls", "tls-roots"] }
69
+ tonic = { workspace = true, features = ["tls-ring", "tls-native-roots"] }
69
70
  tracing = "0.1"
70
71
  tracing-subscriber = { version = "0.3", default-features = false, features = ["parking_lot", "env-filter", "registry", "ansi"] }
71
72
  url = "2.2"
@@ -91,10 +92,11 @@ path = "../fsm"
91
92
  assert_matches = "1.4"
92
93
  bimap = "0.6.1"
93
94
  clap = { version = "4.0", features = ["derive"] }
94
- criterion = "0.5"
95
+ criterion = { version = "0.6", features = ["async", "async_tokio"] }
95
96
  rstest = "0.25"
96
97
  temporal-sdk-core-test-utils = { path = "../test-utils" }
97
98
  temporal-sdk = { path = "../sdk" }
99
+ tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process", "test-util"] }
98
100
  tokio-stream = { version = "0.1", features = ["net"] }
99
101
 
100
102
  [[test]]
@@ -1,10 +1,19 @@
1
- use criterion::{Criterion, criterion_group, criterion_main};
1
+ use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
2
2
  use futures_util::StreamExt;
3
- use std::time::Duration;
3
+ use std::{
4
+ sync::{Arc, mpsc},
5
+ thread,
6
+ time::Duration,
7
+ };
4
8
  use temporal_sdk::{WfContext, WorkflowFunction};
5
- use temporal_sdk_core::replay::HistoryForReplay;
9
+ use temporal_sdk_core::{CoreRuntime, replay::HistoryForReplay};
10
+ use temporal_sdk_core_api::telemetry::metrics::{
11
+ MetricKeyValue, MetricParametersBuilder, NewAttributes,
12
+ };
6
13
  use temporal_sdk_core_protos::DEFAULT_WORKFLOW_TYPE;
7
- use temporal_sdk_core_test_utils::{canned_histories, replay_sdk_worker};
14
+ use temporal_sdk_core_test_utils::{
15
+ DONT_AUTO_INIT_INTEG_TELEM, canned_histories, prom_metrics, replay_sdk_worker,
16
+ };
8
17
 
9
18
  pub fn criterion_benchmark(c: &mut Criterion) {
10
19
  let tokio_runtime = tokio::runtime::Builder::new_current_thread()
@@ -12,6 +21,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
12
21
  .build()
13
22
  .unwrap();
14
23
  let _g = tokio_runtime.enter();
24
+ DONT_AUTO_INIT_INTEG_TELEM.set(true);
15
25
 
16
26
  let num_timers = 10;
17
27
  let t = canned_histories::long_sequential_timers(num_timers as usize);
@@ -21,14 +31,17 @@ pub fn criterion_benchmark(c: &mut Criterion) {
21
31
  );
22
32
 
23
33
  c.bench_function("Small history replay", |b| {
24
- b.iter(|| {
25
- tokio_runtime.block_on(async {
34
+ b.to_async(&tokio_runtime).iter_batched(
35
+ || {
26
36
  let func = timers_wf(num_timers);
27
- let mut worker = replay_sdk_worker([hist.clone()]);
37
+ (func, replay_sdk_worker([hist.clone()]))
38
+ },
39
+ |(func, mut worker)| async move {
28
40
  worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
29
41
  worker.run().await.unwrap();
30
- })
31
- })
42
+ },
43
+ BatchSize::SmallInput,
44
+ )
32
45
  });
33
46
 
34
47
  let num_tasks = 50;
@@ -39,18 +52,104 @@ pub fn criterion_benchmark(c: &mut Criterion) {
39
52
  );
40
53
 
41
54
  c.bench_function("Large payloads history replay", |b| {
42
- b.iter(|| {
43
- tokio_runtime.block_on(async {
55
+ b.to_async(&tokio_runtime).iter_batched(
56
+ || {
44
57
  let func = big_signals_wf(num_tasks);
45
- let mut worker = replay_sdk_worker([hist.clone()]);
58
+ (func, replay_sdk_worker([hist.clone()]))
59
+ },
60
+ |(func, mut worker)| async move {
46
61
  worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
47
62
  worker.run().await.unwrap();
48
- })
49
- })
63
+ },
64
+ BatchSize::SmallInput,
65
+ )
50
66
  });
51
67
  }
52
68
 
53
- criterion_group!(benches, criterion_benchmark);
69
+ pub fn bench_metrics(c: &mut Criterion) {
70
+ DONT_AUTO_INIT_INTEG_TELEM.set(true);
71
+ let tokio_runtime = tokio::runtime::Builder::new_current_thread()
72
+ .enable_all()
73
+ .build()
74
+ .unwrap();
75
+ let _tokio = tokio_runtime.enter();
76
+ let (mut telemopts, addr, _aborter) = prom_metrics(None);
77
+ telemopts.logging = None;
78
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
79
+ let meter = rt.telemetry().get_metric_meter().unwrap();
80
+
81
+ c.bench_function("Record with new attributes on each call", move |b| {
82
+ b.iter_batched(
83
+ || {
84
+ let c = meter.counter(
85
+ MetricParametersBuilder::default()
86
+ .name("c")
87
+ .build()
88
+ .unwrap(),
89
+ );
90
+ let h = meter.histogram(
91
+ MetricParametersBuilder::default()
92
+ .name("h")
93
+ .build()
94
+ .unwrap(),
95
+ );
96
+ let g = meter.gauge(
97
+ MetricParametersBuilder::default()
98
+ .name("g")
99
+ .build()
100
+ .unwrap(),
101
+ );
102
+
103
+ let vals = [1, 2, 3, 4, 5];
104
+ let labels = ["l1", "l2"];
105
+
106
+ let (start_tx, start_rx) = mpsc::channel();
107
+ let start_rx = Arc::new(std::sync::Mutex::new(start_rx));
108
+
109
+ let mut thread_handles = Vec::new();
110
+ for _ in 0..3 {
111
+ let c = c.clone();
112
+ let h = h.clone();
113
+ let g = g.clone();
114
+ let meter = meter.clone();
115
+ let start_rx = start_rx.clone();
116
+
117
+ let handle = thread::spawn(move || {
118
+ // Wait for start signal
119
+ let _ = start_rx.lock().unwrap().recv();
120
+
121
+ for _ in 1..=100 {
122
+ for &val in &vals {
123
+ for &label in &labels {
124
+ let attribs = meter.new_attributes(NewAttributes::from(vec![
125
+ MetricKeyValue::new("label", label),
126
+ ]));
127
+ c.add(val, &attribs);
128
+ h.record(val, &attribs);
129
+ g.record(val, &attribs);
130
+ }
131
+ }
132
+ }
133
+ });
134
+ thread_handles.push(handle);
135
+ }
136
+
137
+ (start_tx, thread_handles)
138
+ },
139
+ |(start_tx, thread_handles)| {
140
+ for _ in 0..3 {
141
+ let _ = start_tx.send(());
142
+ }
143
+ for handle in thread_handles {
144
+ let _ = handle.join();
145
+ }
146
+ },
147
+ BatchSize::SmallInput,
148
+ )
149
+ });
150
+ }
151
+
152
+ criterion_group!(benches, criterion_benchmark, bench_metrics);
54
153
  criterion_main!(benches);
55
154
 
56
155
  fn timers_wf(num_timers: u32) -> WorkflowFunction {
@@ -6,7 +6,7 @@ use crate::{
6
6
  gen_assert_and_reply, mock_manual_poller, mock_poller, mock_poller_from_resps,
7
7
  mock_sdk_cfg, mock_worker, poll_and_reply, single_hist_mock_sg, test_worker_cfg,
8
8
  },
9
- worker::client::mocks::{mock_manual_workflow_client, mock_workflow_client},
9
+ worker::client::mocks::{mock_manual_worker_client, mock_worker_client},
10
10
  };
11
11
  use futures_util::FutureExt;
12
12
  use itertools::Itertools;
@@ -86,7 +86,7 @@ fn three_tasks() -> VecDeque<PollActivityTaskQueueResponse> {
86
86
  async fn max_activities_respected() {
87
87
  let _task_q = "q";
88
88
  let mut tasks = three_tasks();
89
- let mut mock_client = mock_workflow_client();
89
+ let mut mock_client = mock_worker_client();
90
90
  mock_client
91
91
  .expect_poll_activity_task()
92
92
  .times(3)
@@ -122,7 +122,7 @@ async fn max_activities_respected() {
122
122
 
123
123
  #[tokio::test]
124
124
  async fn activity_not_found_returns_ok() {
125
- let mut mock_client = mock_workflow_client();
125
+ let mut mock_client = mock_worker_client();
126
126
  // Mock won't even be called, since we weren't tracking activity
127
127
  mock_client.expect_complete_activity_task().times(0);
128
128
 
@@ -139,7 +139,7 @@ async fn activity_not_found_returns_ok() {
139
139
 
140
140
  #[tokio::test]
141
141
  async fn heartbeats_report_cancels_only_once() {
142
- let mut mock_client = mock_workflow_client();
142
+ let mut mock_client = mock_worker_client();
143
143
  mock_client
144
144
  .expect_record_activity_heartbeat()
145
145
  .times(2)
@@ -265,7 +265,7 @@ async fn activity_cancel_interrupts_poll() {
265
265
  .times(3)
266
266
  .returning(move || poll_resps.pop_front().unwrap());
267
267
 
268
- let mut mock_client = mock_manual_workflow_client();
268
+ let mut mock_client = mock_manual_worker_client();
269
269
  mock_client
270
270
  .expect_record_activity_heartbeat()
271
271
  .times(1)
@@ -323,7 +323,7 @@ async fn activity_cancel_interrupts_poll() {
323
323
 
324
324
  #[tokio::test]
325
325
  async fn activity_poll_timeout_retries() {
326
- let mock_client = mock_workflow_client();
326
+ let mock_client = mock_worker_client();
327
327
  let mut calls = 0;
328
328
  let mut mock_act_poller = mock_poller();
329
329
  mock_act_poller.expect_poll().times(3).returning(move || {
@@ -352,7 +352,7 @@ async fn many_concurrent_heartbeat_cancels() {
352
352
  // them after a few successful heartbeats
353
353
  const CONCURRENCY_NUM: usize = 5;
354
354
 
355
- let mut mock_client = mock_manual_workflow_client();
355
+ let mut mock_client = mock_manual_worker_client();
356
356
  let mut poll_resps = VecDeque::from(
357
357
  (0..CONCURRENCY_NUM)
358
358
  .map(|i| {
@@ -516,7 +516,7 @@ async fn activity_timeout_no_double_resolve() {
516
516
 
517
517
  #[tokio::test]
518
518
  async fn can_heartbeat_acts_during_shutdown() {
519
- let mut mock_client = mock_workflow_client();
519
+ let mut mock_client = mock_worker_client();
520
520
  mock_client
521
521
  .expect_record_activity_heartbeat()
522
522
  .times(1)
@@ -567,7 +567,7 @@ async fn can_heartbeat_acts_during_shutdown() {
567
567
  #[tokio::test]
568
568
  async fn complete_act_with_fail_flushes_heartbeat() {
569
569
  let last_hb = 50;
570
- let mut mock_client = mock_workflow_client();
570
+ let mut mock_client = mock_worker_client();
571
571
  let last_seen_payload = Rc::new(RefCell::new(None));
572
572
  let lsp = last_seen_payload.clone();
573
573
  mock_client
@@ -622,7 +622,7 @@ async fn complete_act_with_fail_flushes_heartbeat() {
622
622
  #[tokio::test]
623
623
  async fn max_tq_acts_set_passed_to_poll_properly() {
624
624
  let rate = 9.28;
625
- let mut mock_client = mock_workflow_client();
625
+ let mut mock_client = mock_worker_client();
626
626
  mock_client
627
627
  .expect_poll_activity_task()
628
628
  .returning(move |_, ao| {
@@ -659,7 +659,7 @@ async fn no_eager_activities_requested_when_worker_options_disable_it(
659
659
  let num_eager_requested = Arc::new(AtomicUsize::new(0));
660
660
  let num_eager_requested_clone = num_eager_requested.clone();
661
661
 
662
- let mut mock = mock_workflow_client();
662
+ let mut mock = mock_worker_client();
663
663
  mock.expect_complete_workflow_task()
664
664
  .times(1)
665
665
  .returning(move |req| {
@@ -747,7 +747,7 @@ async fn activity_tasks_from_completion_are_delivered() {
747
747
  // Clone it to move into the callback below
748
748
  let num_eager_requested_clone = num_eager_requested.clone();
749
749
 
750
- let mut mock = mock_workflow_client();
750
+ let mut mock = mock_worker_client();
751
751
  mock.expect_complete_workflow_task()
752
752
  .times(1)
753
753
  .returning(move |req| {
@@ -876,7 +876,7 @@ async fn activity_tasks_from_completion_reserve_slots() {
876
876
  t.add_full_wf_task();
877
877
  t.add_workflow_execution_completed();
878
878
 
879
- let mut mock = mock_workflow_client();
879
+ let mut mock = mock_worker_client();
880
880
  // Set up two tasks to be returned via normal activity polling
881
881
  let act_tasks = VecDeque::from(vec![
882
882
  PollActivityTaskQueueResponse {
@@ -1004,7 +1004,7 @@ async fn activity_tasks_from_completion_reserve_slots() {
1004
1004
 
1005
1005
  #[tokio::test]
1006
1006
  async fn retryable_net_error_exhaustion_is_nonfatal() {
1007
- let mut mock_client = mock_workflow_client();
1007
+ let mut mock_client = mock_worker_client();
1008
1008
  mock_client
1009
1009
  .expect_complete_activity_task()
1010
1010
  .times(1)
@@ -1033,7 +1033,7 @@ async fn retryable_net_error_exhaustion_is_nonfatal() {
1033
1033
 
1034
1034
  #[tokio::test]
1035
1035
  async fn cant_complete_activity_with_unset_result_payload() {
1036
- let mut mock_client = mock_workflow_client();
1036
+ let mut mock_client = mock_worker_client();
1037
1037
  mock_client
1038
1038
  .expect_poll_activity_task()
1039
1039
  .returning(move |_, _| {
@@ -1076,7 +1076,7 @@ async fn graceful_shutdown(#[values(true, false)] at_max_outstanding: bool) {
1076
1076
  .times(1)
1077
1077
  .returning(move || None);
1078
1078
  // They shall all be reported as failed
1079
- let mut mock_client = mock_workflow_client();
1079
+ let mut mock_client = mock_worker_client();
1080
1080
  mock_client
1081
1081
  .expect_fail_activity_task()
1082
1082
  .times(3)
@@ -1153,7 +1153,7 @@ async fn activities_must_be_flushed_to_server_on_shutdown(#[values(true, false)]
1153
1153
  .expect_poll()
1154
1154
  .times(1)
1155
1155
  .returning(move || None);
1156
- let mut mock_client = mock_manual_workflow_client();
1156
+ let mut mock_client = mock_manual_worker_client();
1157
1157
  mock_client
1158
1158
  .expect_complete_activity_task()
1159
1159
  .times(1)
@@ -1251,7 +1251,7 @@ async fn pass_activity_summary_to_metadata() {
1251
1251
 
1252
1252
  #[tokio::test]
1253
1253
  async fn heartbeat_response_can_be_paused() {
1254
- let mut mock_client = mock_workflow_client();
1254
+ let mut mock_client = mock_worker_client();
1255
1255
  // First heartbeat returns pause only
1256
1256
  mock_client
1257
1257
  .expect_record_activity_heartbeat()