@temporalio/core-bridge 1.11.6 → 1.11.8

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 (191) hide show
  1. package/Cargo.lock +902 -468
  2. package/package.json +3 -3
  3. package/releases/aarch64-apple-darwin/index.node +0 -0
  4. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  5. package/releases/x86_64-apple-darwin/index.node +0 -0
  6. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  7. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  8. package/sdk-core/.cargo/config.toml +5 -0
  9. package/sdk-core/.github/workflows/per-pr.yml +59 -5
  10. package/sdk-core/Cargo.toml +3 -2
  11. package/sdk-core/client/Cargo.toml +3 -3
  12. package/sdk-core/client/src/lib.rs +154 -161
  13. package/sdk-core/client/src/metrics.rs +15 -8
  14. package/sdk-core/client/src/proxy.rs +1 -1
  15. package/sdk-core/client/src/raw.rs +176 -33
  16. package/sdk-core/client/src/retry.rs +102 -465
  17. package/sdk-core/client/src/worker_registry/mod.rs +2 -2
  18. package/sdk-core/client/src/workflow_handle/mod.rs +19 -1
  19. package/sdk-core/core/Cargo.toml +12 -14
  20. package/sdk-core/core/benches/workflow_replay.rs +1 -1
  21. package/sdk-core/core/src/abstractions.rs +2 -2
  22. package/sdk-core/core/src/core_tests/activity_tasks.rs +99 -46
  23. package/sdk-core/core/src/core_tests/child_workflows.rs +68 -9
  24. package/sdk-core/core/src/core_tests/determinism.rs +2 -2
  25. package/sdk-core/core/src/core_tests/local_activities.rs +20 -33
  26. package/sdk-core/core/src/core_tests/mod.rs +7 -8
  27. package/sdk-core/core/src/core_tests/queries.rs +79 -79
  28. package/sdk-core/core/src/core_tests/replay_flag.rs +5 -5
  29. package/sdk-core/core/src/core_tests/updates.rs +6 -6
  30. package/sdk-core/core/src/core_tests/workers.rs +19 -22
  31. package/sdk-core/core/src/core_tests/workflow_cancels.rs +3 -3
  32. package/sdk-core/core/src/core_tests/workflow_tasks.rs +154 -106
  33. package/sdk-core/core/src/ephemeral_server/mod.rs +66 -10
  34. package/sdk-core/core/src/internal_flags.rs +103 -12
  35. package/sdk-core/core/src/lib.rs +21 -13
  36. package/sdk-core/core/src/pollers/mod.rs +200 -6
  37. package/sdk-core/core/src/pollers/poll_buffer.rs +32 -8
  38. package/sdk-core/core/src/protosext/mod.rs +7 -7
  39. package/sdk-core/core/src/protosext/protocol_messages.rs +2 -2
  40. package/sdk-core/core/src/replay/mod.rs +8 -9
  41. package/sdk-core/core/src/retry_logic.rs +8 -6
  42. package/sdk-core/core/src/telemetry/log_export.rs +4 -4
  43. package/sdk-core/core/src/telemetry/metrics.rs +111 -25
  44. package/sdk-core/core/src/telemetry/mod.rs +11 -4
  45. package/sdk-core/core/src/telemetry/otel.rs +108 -144
  46. package/sdk-core/core/src/telemetry/prometheus_server.rs +1 -4
  47. package/sdk-core/core/src/test_help/mod.rs +27 -21
  48. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +7 -5
  49. package/sdk-core/core/src/worker/activities/local_activities.rs +9 -9
  50. package/sdk-core/core/src/worker/activities.rs +34 -46
  51. package/sdk-core/core/src/worker/client/mocks.rs +24 -2
  52. package/sdk-core/core/src/worker/client.rs +169 -33
  53. package/sdk-core/core/src/worker/mod.rs +132 -56
  54. package/sdk-core/core/src/worker/nexus.rs +410 -0
  55. package/sdk-core/core/src/worker/tuner/resource_based.rs +27 -5
  56. package/sdk-core/core/src/worker/tuner.rs +29 -2
  57. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +8 -3
  58. package/sdk-core/core/src/worker/workflow/history_update.rs +5 -8
  59. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +83 -87
  60. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +38 -38
  61. package/sdk-core/core/src/worker/workflow/machines/cancel_nexus_op_state_machine.rs +117 -0
  62. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +8 -18
  63. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +114 -108
  64. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +16 -31
  65. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -14
  66. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +8 -15
  67. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +34 -75
  68. package/sdk-core/core/src/worker/workflow/machines/mod.rs +26 -48
  69. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +10 -17
  70. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +543 -0
  71. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +22 -31
  72. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +53 -51
  73. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +40 -45
  74. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  75. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +8 -10
  76. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +24 -30
  77. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +182 -116
  78. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -8
  79. package/sdk-core/core/src/worker/workflow/managed_run.rs +75 -45
  80. package/sdk-core/core/src/worker/workflow/mod.rs +104 -55
  81. package/sdk-core/core/src/worker/workflow/run_cache.rs +23 -4
  82. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +4 -4
  83. package/sdk-core/core/src/worker/workflow/wft_poller.rs +3 -3
  84. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +32 -13
  85. package/sdk-core/core-api/Cargo.toml +2 -3
  86. package/sdk-core/core-api/src/errors.rs +22 -20
  87. package/sdk-core/core-api/src/lib.rs +24 -5
  88. package/sdk-core/core-api/src/telemetry/metrics.rs +27 -1
  89. package/sdk-core/core-api/src/telemetry.rs +37 -3
  90. package/sdk-core/core-api/src/worker.rs +36 -3
  91. package/sdk-core/docker/docker-compose-ci.yaml +25 -0
  92. package/sdk-core/etc/otel-collector-ci.yaml +36 -0
  93. package/sdk-core/etc/otel-collector-config.yaml +3 -3
  94. package/sdk-core/etc/prometheus.yaml +1 -1
  95. package/sdk-core/fsm/Cargo.toml +1 -1
  96. package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +3 -4
  98. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  99. package/sdk-core/fsm/rustfsm_trait/Cargo.toml +1 -1
  100. package/sdk-core/sdk/Cargo.toml +1 -2
  101. package/sdk-core/sdk/src/activity_context.rs +1 -1
  102. package/sdk-core/sdk/src/interceptors.rs +1 -1
  103. package/sdk-core/sdk/src/lib.rs +126 -54
  104. package/sdk-core/sdk/src/workflow_context/options.rs +184 -74
  105. package/sdk-core/sdk/src/workflow_context.rs +193 -79
  106. package/sdk-core/sdk/src/workflow_future.rs +151 -131
  107. package/sdk-core/sdk-core-protos/Cargo.toml +3 -4
  108. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -1
  109. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/account/v1/message.proto +46 -0
  110. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +254 -5
  111. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +108 -2
  112. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +94 -15
  113. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +102 -4
  114. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/nexus/v1/message.proto +84 -0
  115. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +25 -10
  116. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +14 -1
  117. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/resource/v1/message.proto +25 -0
  118. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/sink/v1/message.proto +41 -0
  119. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/usage/v1/message.proto +59 -0
  120. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -0
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +135 -0
  122. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/push-to-buf.yml +20 -0
  123. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-delete-release.yml +13 -0
  124. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-publish-release.yml +13 -0
  125. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +13 -21
  126. package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +2 -2
  127. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +1 -0
  128. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +3386 -1047
  129. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +3529 -1144
  130. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +39 -1
  131. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +6 -0
  132. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +39 -1
  133. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +252 -0
  134. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +1 -0
  135. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +6 -0
  136. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +96 -0
  137. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +2 -0
  138. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  139. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/nexus.proto +42 -0
  140. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -0
  141. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +43 -2
  142. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +13 -1
  143. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +14 -0
  144. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +70 -12
  145. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +12 -0
  146. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/query/v1/message.proto +9 -2
  147. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +46 -2
  148. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +206 -0
  149. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +482 -97
  150. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +230 -43
  151. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/core_interface.proto +6 -0
  152. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/nexus/nexus.proto +71 -0
  153. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +46 -2
  154. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +55 -9
  155. package/sdk-core/sdk-core-protos/src/history_builder.rs +5 -5
  156. package/sdk-core/sdk-core-protos/src/history_info.rs +5 -6
  157. package/sdk-core/sdk-core-protos/src/lib.rs +414 -34
  158. package/sdk-core/sdk-core-protos/src/task_token.rs +1 -1
  159. package/sdk-core/test-utils/Cargo.toml +3 -11
  160. package/sdk-core/test-utils/src/canned_histories.rs +1 -1
  161. package/sdk-core/test-utils/src/lib.rs +159 -85
  162. package/sdk-core/tests/fuzzy_workflow.rs +3 -3
  163. package/sdk-core/tests/heavy_tests.rs +3 -3
  164. package/sdk-core/tests/integ_tests/client_tests.rs +171 -20
  165. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +45 -39
  166. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +7 -6
  167. package/sdk-core/tests/integ_tests/metrics_tests.rs +492 -35
  168. package/sdk-core/tests/integ_tests/polling_tests.rs +7 -5
  169. package/sdk-core/tests/integ_tests/queries_tests.rs +14 -17
  170. package/sdk-core/tests/integ_tests/update_tests.rs +47 -44
  171. package/sdk-core/tests/integ_tests/visibility_tests.rs +4 -3
  172. package/sdk-core/tests/integ_tests/worker_tests.rs +5 -5
  173. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +15 -13
  174. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +28 -14
  175. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +7 -1
  176. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +57 -4
  177. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  178. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +24 -18
  179. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +506 -0
  180. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +1 -1
  181. package/sdk-core/tests/integ_tests/workflow_tests/priority.rs +104 -0
  182. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +34 -31
  183. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
  184. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -7
  185. package/sdk-core/tests/integ_tests/workflow_tests.rs +152 -116
  186. package/sdk-core/tests/main.rs +36 -6
  187. package/sdk-core/tests/runner.rs +30 -9
  188. package/src/conversions/slot_supplier_bridge.rs +4 -0
  189. package/src/conversions.rs +1 -0
  190. package/src/worker.rs +5 -7
  191. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +0 -78
@@ -1,18 +1,22 @@
1
1
  use crate::{
2
+ MetricsContext,
2
3
  telemetry::metrics::workflow_type,
3
4
  worker::workflow::{
5
+ HistoryUpdate, LocalActivityRequestSink, PermittedWFT, RequestEvictMsg, RunBasics,
4
6
  managed_run::{ManagedRun, RunUpdateAct},
5
- HistoryUpdate, LocalActivityRequestSink, PermittedWFT, RunBasics,
6
7
  },
7
- MetricsContext,
8
8
  };
9
9
  use lru::LruCache;
10
10
  use std::{num::NonZeroUsize, rc::Rc, sync::Arc};
11
11
  use temporal_sdk_core_api::worker::WorkerConfig;
12
- use temporal_sdk_core_protos::temporal::api::workflowservice::v1::get_system_info_response;
12
+ use temporal_sdk_core_protos::{
13
+ coresdk::workflow_activation::remove_from_cache::EvictionReason,
14
+ temporal::api::workflowservice::v1::get_system_info_response,
15
+ };
13
16
 
14
17
  pub(super) struct RunCache {
15
18
  worker_config: Arc<WorkerConfig>,
19
+ sdk_name_and_version: (String, String),
16
20
  server_capabilities: get_system_info_response::Capabilities,
17
21
  /// Run id -> Data
18
22
  runs: LruCache<String, ManagedRun>,
@@ -24,6 +28,7 @@ pub(super) struct RunCache {
24
28
  impl RunCache {
25
29
  pub(super) fn new(
26
30
  worker_config: Arc<WorkerConfig>,
31
+ sdk_name_and_version: (String, String),
27
32
  server_capabilities: get_system_info_response::Capabilities,
28
33
  local_activity_request_sink: impl LocalActivityRequestSink,
29
34
  metrics: MetricsContext,
@@ -37,6 +42,7 @@ impl RunCache {
37
42
  };
38
43
  Self {
39
44
  worker_config,
45
+ sdk_name_and_version,
40
46
  server_capabilities,
41
47
  runs: LruCache::new(
42
48
  NonZeroUsize::new(lru_size).expect("LRU size is guaranteed positive"),
@@ -70,6 +76,8 @@ impl RunCache {
70
76
  history: HistoryUpdate::dummy(),
71
77
  metrics,
72
78
  capabilities: &self.server_capabilities,
79
+ sdk_name: &self.sdk_name_and_version.0,
80
+ sdk_version: &self.sdk_name_and_version.1,
73
81
  },
74
82
  pwft,
75
83
  self.local_activity_request_sink.clone(),
@@ -84,7 +92,18 @@ impl RunCache {
84
92
  pub(super) fn remove(&mut self, k: &str) -> Option<ManagedRun> {
85
93
  let r = self.runs.pop(k);
86
94
  self.metrics.cache_size(self.len() as u64);
87
- self.metrics.cache_eviction();
95
+ if let Some(rh) = &r {
96
+ // A workflow completing normally doesn't count as a forced eviction.
97
+ if !matches!(
98
+ rh.trying_to_evict(),
99
+ Some(RequestEvictMsg {
100
+ reason: EvictionReason::WorkflowExecutionEnding,
101
+ ..
102
+ })
103
+ ) {
104
+ self.metrics.forced_cache_eviction();
105
+ }
106
+ }
88
107
  r
89
108
  }
90
109
 
@@ -4,15 +4,15 @@ use crate::{
4
4
  worker::{
5
5
  client::WorkerClient,
6
6
  workflow::{
7
- history_update::HistoryPaginator, CacheMissFetchReq, HistoryUpdate, NextPageReq,
8
- PermittedWFT,
7
+ CacheMissFetchReq, HistoryUpdate, NextPageReq, PermittedWFT,
8
+ history_update::HistoryPaginator,
9
9
  },
10
10
  },
11
11
  };
12
- use futures_util::{stream, stream::PollNext, FutureExt, Stream, StreamExt};
12
+ use futures_util::{FutureExt, Stream, StreamExt, stream, stream::PollNext};
13
13
  use std::{future, sync::Arc};
14
14
  use temporal_sdk_core_api::worker::WorkflowSlotKind;
15
- use temporal_sdk_core_protos::{coresdk::WorkflowSlotInfo, TaskToken};
15
+ use temporal_sdk_core_protos::{TaskToken, coresdk::WorkflowSlotInfo};
16
16
  use tracing::Span;
17
17
 
18
18
  /// Transforms incoming validated WFTs and history fetching requests into [PermittedWFT]s ready
@@ -1,10 +1,10 @@
1
1
  use crate::{
2
+ MetricsContext,
2
3
  abstractions::OwnedMeteredSemPermit,
3
4
  pollers::{BoxedWFPoller, Poller},
4
5
  protosext::ValidPollWFTQResponse,
5
- MetricsContext,
6
6
  };
7
- use futures_util::{stream, Stream};
7
+ use futures_util::{Stream, stream};
8
8
  use temporal_sdk_core_api::worker::WorkflowSlotKind;
9
9
  use temporal_sdk_core_protos::temporal::api::workflowservice::v1::PollWorkflowTaskQueueResponse;
10
10
 
@@ -78,7 +78,7 @@ mod tests {
78
78
  abstractions::tests::fixed_size_permit_dealer, pollers::MockPermittedPollBuffer,
79
79
  test_help::mock_poller,
80
80
  };
81
- use futures_util::{pin_mut, StreamExt};
81
+ use futures_util::{StreamExt, pin_mut};
82
82
  use std::sync::Arc;
83
83
  use temporal_sdk_core_api::worker::WorkflowSlotKind;
84
84
 
@@ -1,4 +1,5 @@
1
1
  use crate::{
2
+ MetricsContext,
2
3
  abstractions::dbg_panic,
3
4
  worker::workflow::{
4
5
  managed_run::RunUpdateAct,
@@ -6,11 +7,10 @@ use crate::{
6
7
  wft_extraction::{HistfetchRC, HistoryFetchReq, WFTExtractorOutput},
7
8
  *,
8
9
  },
9
- MetricsContext,
10
10
  };
11
- use futures_util::{stream, stream::PollNext, Stream, StreamExt};
11
+ use futures_util::{Stream, StreamExt, stream, stream::PollNext};
12
12
  use std::{collections::VecDeque, fmt::Debug, future, sync::Arc};
13
- use temporal_sdk_core_api::errors::PollWfError;
13
+ use temporal_sdk_core_api::errors::PollError;
14
14
  use temporal_sdk_core_protos::coresdk::workflow_activation::remove_from_cache::EvictionReason;
15
15
  use tokio_util::sync::CancellationToken;
16
16
  use tracing::{Level, Span};
@@ -64,7 +64,7 @@ impl WFStream {
64
64
  wft_stream: impl Stream<Item = Result<WFTExtractorOutput, tonic::Status>> + Send + 'static,
65
65
  local_rx: impl Stream<Item = LocalInput> + Send + 'static,
66
66
  local_activity_request_sink: impl LocalActivityRequestSink,
67
- ) -> impl Stream<Item = Result<WFStreamOutput, PollWfError>> {
67
+ ) -> impl Stream<Item = Result<WFStreamOutput, PollError>> {
68
68
  let all_inputs = stream::select_with_strategy(
69
69
  local_rx.map(Into::into),
70
70
  wft_stream
@@ -82,11 +82,12 @@ impl WFStream {
82
82
  all_inputs: impl Stream<Item = WFStreamInput>,
83
83
  basics: WorkflowBasics,
84
84
  local_activity_request_sink: impl LocalActivityRequestSink,
85
- ) -> impl Stream<Item = Result<WFStreamOutput, PollWfError>> {
85
+ ) -> impl Stream<Item = Result<WFStreamOutput, PollError>> {
86
86
  let mut state = WFStream {
87
87
  buffered_polls_need_cache_slot: Default::default(),
88
88
  runs: RunCache::new(
89
89
  basics.worker_config.clone(),
90
+ (basics.sdk_name.clone(), basics.sdk_version.clone()),
90
91
  basics.server_capabilities,
91
92
  local_activity_request_sink,
92
93
  basics.metrics.clone(),
@@ -165,7 +166,7 @@ impl WFStream {
165
166
  None
166
167
  }
167
168
  WFStreamInput::PollerError(e) => {
168
- return Err(PollWfError::TonicError(e));
169
+ return Err(PollError::TonicError(e));
169
170
  }
170
171
  };
171
172
 
@@ -174,7 +175,7 @@ impl WFStream {
174
175
 
175
176
  if state.shutdown_done() {
176
177
  info!("Workflow shutdown is done");
177
- return Err(PollWfError::ShutDown);
178
+ return Err(PollError::ShutDown);
178
179
  }
179
180
 
180
181
  Ok(WFStreamOutput {
@@ -184,7 +185,7 @@ impl WFStream {
184
185
  })
185
186
  .inspect(|o| {
186
187
  if let Some(e) = o.as_ref().err() {
187
- if !matches!(e, PollWfError::ShutDown) {
188
+ if !matches!(e, PollError::ShutDown) {
188
189
  error!(
189
190
  "Workflow processing encountered fatal error and must shut down {:?}",
190
191
  e
@@ -193,7 +194,7 @@ impl WFStream {
193
194
  }
194
195
  })
195
196
  // Stop the stream once we have shut down
196
- .take_while(|o| future::ready(!matches!(o, Err(PollWfError::ShutDown))))
197
+ .take_while(|o| future::ready(!matches!(o, Err(PollError::ShutDown))))
197
198
  }
198
199
 
199
200
  /// Instantiate or update run machines with a new WFT
@@ -264,7 +265,12 @@ impl WFStream {
264
265
  commands,
265
266
  used_flags,
266
267
  ..
267
- } => match rh.successful_completion(commands, used_flags, complete.response_tx) {
268
+ } => match rh.successful_completion(
269
+ commands,
270
+ used_flags,
271
+ complete.response_tx,
272
+ false,
273
+ ) {
268
274
  Ok(acts) => acts,
269
275
  Err(npr) => {
270
276
  self.runs_needing_fetching
@@ -321,7 +327,6 @@ impl WFStream {
321
327
 
322
328
  let mut res = None;
323
329
 
324
- // If we reported to server, we always want to mark it complete.
325
330
  let maybe_t = self.complete_wft(run_id, report.wft_report_status);
326
331
  // Augment the WFT from complete with the permit if both exist
327
332
  let wft_from_complete = wft_from_complete.and_then(|wft| {
@@ -378,6 +383,20 @@ impl WFStream {
378
383
  if let Some(rh) = self.runs.get_mut(run_id) {
379
384
  // Attempt to produce the next activation if needed
380
385
  res = rh.check_more_activations();
386
+ // If there's no more work and we reported workflow completion to server, evict.
387
+ if res.is_none()
388
+ && rh.workflow_is_finished()
389
+ && matches!(report.wft_report_status, WFTReportStatus::Reported { .. })
390
+ {
391
+ res = rh
392
+ .request_eviction(RequestEvictMsg {
393
+ run_id: run_id.to_string(),
394
+ message: "Workflow completed".to_string(),
395
+ reason: EvictionReason::WorkflowExecutionEnding,
396
+ auto_reply_fail_tt: None,
397
+ })
398
+ .into_run_update_resp()
399
+ }
381
400
  }
382
401
  }
383
402
  res
@@ -492,7 +511,7 @@ impl WFStream {
492
511
  let num_existing_evictions = self
493
512
  .runs
494
513
  .runs_lru_order()
495
- .filter(|(_, h)| h.is_trying_to_evict())
514
+ .filter(|(_, h)| h.trying_to_evict().is_some())
496
515
  .count();
497
516
  let mut num_evicts_needed = num_in_buff.saturating_sub(num_existing_evictions);
498
517
  for (rid, handle) in self.runs.runs_lru_order() {
@@ -546,7 +565,7 @@ impl WFStream {
546
565
  if let Some(r) = self.runs.peek(run_id) {
547
566
  info!(run_id, wft=?r.wft(), activation=?r.activation(),
548
567
  buffered_wft=r.has_buffered_wft(),
549
- trying_to_evict=r.is_trying_to_evict(), more_work=r.more_pending_work());
568
+ trying_to_evict=r.trying_to_evict().is_some(), more_work=r.more_pending_work());
550
569
  } else {
551
570
  info!(run_id, "Run not found");
552
571
  }
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "temporal-sdk-core-api"
3
3
  version = "0.1.0"
4
- edition = "2021"
4
+ edition = "2024"
5
5
  authors = ["Spencer Judge <spencer@temporal.io>"]
6
6
  license-file = { workspace = true }
7
7
  description = "Interface definitions for the Temporal Core SDK"
@@ -21,9 +21,8 @@ derive_builder = { workspace = true }
21
21
  derive_more = { workspace = true }
22
22
  opentelemetry = { workspace = true, optional = true }
23
23
  prost = { workspace = true }
24
- prost-types = { workspace = true }
25
24
  serde_json = "1.0"
26
- thiserror = "1.0"
25
+ thiserror = { workspace = true }
27
26
  tonic = { workspace = true }
28
27
  tracing-core = "0.1"
29
28
  url = "2.3"
@@ -13,30 +13,18 @@ pub enum WorkerValidationError {
13
13
  },
14
14
  }
15
15
 
16
- /// Errors thrown by [crate::Worker::poll_workflow_activation]
16
+ /// Errors thrown by [crate::Worker] polling methods
17
17
  #[derive(thiserror::Error, Debug)]
18
- pub enum PollWfError {
19
- /// [crate::Worker::shutdown] was called, and there are no more replay tasks to be handled. Lang
20
- /// must call [crate::Worker::complete_workflow_activation] for any remaining tasks, and then
21
- /// may exit.
22
- #[error("Core is shut down and there are no more workflow replay tasks")]
18
+ pub enum PollError {
19
+ /// [crate::Worker::shutdown] was called, and there are no more tasks to be handled from this
20
+ /// poll function. Lang must call [crate::Worker::complete_workflow_activation],
21
+ /// [crate::Worker::complete_activity_task], or
22
+ /// [crate::Worker::complete_nexus_task] for any remaining tasks, and then may exit.
23
+ #[error("Core is shut down and there are no more tasks of this kind")]
23
24
  ShutDown,
24
25
  /// Unhandled error when calling the temporal server. Core will attempt to retry any non-fatal
25
26
  /// errors, so lang should consider this fatal.
26
- #[error("Unhandled grpc error when workflow polling: {0:?}")]
27
- TonicError(#[from] tonic::Status),
28
- }
29
-
30
- /// Errors thrown by [crate::Worker::poll_activity_task]
31
- #[derive(thiserror::Error, Debug)]
32
- pub enum PollActivityError {
33
- /// [crate::Worker::shutdown] was called, we will no longer fetch new activity tasks. Lang must
34
- /// ensure it is finished with any workflow replay, see [PollWfError::ShutDown]
35
- #[error("Core is shut down")]
36
- ShutDown,
37
- /// Unhandled error when calling the temporal server. Core will attempt to retry any non-fatal
38
- /// errors, so lang should consider this fatal.
39
- #[error("Unhandled grpc error when activity polling: {0:?}")]
27
+ #[error("Unhandled grpc error when polling: {0:?}")]
40
28
  TonicError(#[from] tonic::Status),
41
29
  }
42
30
 
@@ -67,6 +55,20 @@ pub enum CompleteActivityError {
67
55
  },
68
56
  }
69
57
 
58
+ /// Errors thrown by [crate::Worker::complete_nexus_task]
59
+ #[derive(thiserror::Error, Debug)]
60
+ pub enum CompleteNexusError {
61
+ /// Lang SDK sent us a malformed nexus completion. This likely means a bug in the lang sdk.
62
+ #[error("Lang SDK sent us a malformed nexus completion: {reason}")]
63
+ MalformedNexusCompletion {
64
+ /// Reason the completion was malformed
65
+ reason: String,
66
+ },
67
+ /// Nexus has not been enabled on this worker. If a user registers any Nexus handlers, the
68
+ #[error("Nexus is not enabled on this worker")]
69
+ NexusNotEnabled,
70
+ }
71
+
70
72
  /// Errors we can encounter during workflow processing which we may treat as either WFT failures
71
73
  /// or whole-workflow failures depending on user preference.
72
74
  #[derive(Clone, Debug, Eq, PartialEq, Hash)]
@@ -4,14 +4,17 @@ pub mod worker;
4
4
 
5
5
  use crate::{
6
6
  errors::{
7
- CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
7
+ CompleteActivityError, CompleteNexusError, CompleteWfError, PollError,
8
8
  WorkerValidationError,
9
9
  },
10
10
  worker::WorkerConfig,
11
11
  };
12
12
  use temporal_sdk_core_protos::coresdk::{
13
- activity_task::ActivityTask, workflow_activation::WorkflowActivation,
14
- workflow_completion::WorkflowActivationCompletion, ActivityHeartbeat, ActivityTaskCompletion,
13
+ ActivityHeartbeat, ActivityTaskCompletion,
14
+ activity_task::ActivityTask,
15
+ nexus::{NexusTask, NexusTaskCompletion},
16
+ workflow_activation::WorkflowActivation,
17
+ workflow_completion::WorkflowActivationCompletion,
15
18
  };
16
19
 
17
20
  /// This trait is the primary way by which language specific SDKs interact with the core SDK.
@@ -36,14 +39,23 @@ pub trait Worker: Send + Sync {
36
39
  /// & job processing.
37
40
  ///
38
41
  /// Do not call poll concurrently. It handles polling the server concurrently internally.
39
- async fn poll_workflow_activation(&self) -> Result<WorkflowActivation, PollWfError>;
42
+ async fn poll_workflow_activation(&self) -> Result<WorkflowActivation, PollError>;
40
43
 
41
44
  /// Ask the worker for some work, returning an [ActivityTask]. It is then the language SDK's
42
45
  /// responsibility to call the appropriate activity code with the provided inputs. Blocks
43
46
  /// indefinitely until such work is available or [Worker::shutdown] is called.
44
47
  ///
45
48
  /// Do not call poll concurrently. It handles polling the server concurrently internally.
46
- async fn poll_activity_task(&self) -> Result<ActivityTask, PollActivityError>;
49
+ async fn poll_activity_task(&self) -> Result<ActivityTask, PollError>;
50
+
51
+ /// Ask the worker for some nexus related work. It is then the language SDK's
52
+ /// responsibility to call the appropriate nexus operation handler code with the provided
53
+ /// inputs. Blocks indefinitely until such work is available or [Worker::shutdown] is called.
54
+ ///
55
+ /// All tasks must be responded to for shutdown to complete.
56
+ ///
57
+ /// Do not call poll concurrently. It handles polling the server concurrently internally.
58
+ async fn poll_nexus_task(&self) -> Result<NexusTask, PollError>;
47
59
 
48
60
  /// Tell the worker that a workflow activation has completed. May (and should) be freely called
49
61
  /// concurrently. The future may take some time to resolve, as fetching more events might be
@@ -61,6 +73,13 @@ pub trait Worker: Send + Sync {
61
73
  completion: ActivityTaskCompletion,
62
74
  ) -> Result<(), CompleteActivityError>;
63
75
 
76
+ /// Tell the worker that a nexus task has completed. May (and should) be freely called
77
+ /// concurrently.
78
+ async fn complete_nexus_task(
79
+ &self,
80
+ completion: NexusTaskCompletion,
81
+ ) -> Result<(), CompleteNexusError>;
82
+
64
83
  /// Notify the Temporal service that an activity is still alive. Long running activities that
65
84
  /// take longer than `activity_heartbeat_timeout` to finish must call this function in order to
66
85
  /// report progress, otherwise the activity will timeout and a new attempt will be scheduled.
@@ -345,7 +345,7 @@ impl CustomMetricAttributes for NoOpAttributes {
345
345
  #[cfg(feature = "otel_impls")]
346
346
  mod otel_impls {
347
347
  use super::*;
348
- use opentelemetry::{metrics, KeyValue};
348
+ use opentelemetry::{KeyValue, metrics};
349
349
 
350
350
  impl From<MetricKeyValue> for KeyValue {
351
351
  fn from(kv: MetricKeyValue) -> Self {
@@ -377,6 +377,32 @@ mod otel_impls {
377
377
  }
378
378
  }
379
379
 
380
+ impl Gauge for metrics::Gauge<u64> {
381
+ fn record(&self, value: u64, attributes: &MetricAttributes) {
382
+ if let MetricAttributes::OTel { kvs } = attributes {
383
+ self.record(value, kvs);
384
+ } else {
385
+ debug_assert!(
386
+ false,
387
+ "Must use OTel attributes with an OTel metric implementation"
388
+ );
389
+ }
390
+ }
391
+ }
392
+
393
+ impl GaugeF64 for metrics::Gauge<f64> {
394
+ fn record(&self, value: f64, attributes: &MetricAttributes) {
395
+ if let MetricAttributes::OTel { kvs } = attributes {
396
+ self.record(value, kvs);
397
+ } else {
398
+ debug_assert!(
399
+ false,
400
+ "Must use OTel attributes with an OTel metric implementation"
401
+ );
402
+ }
403
+ }
404
+ }
405
+
380
406
  impl Histogram for metrics::Histogram<u64> {
381
407
  fn record(&self, value: u64, attributes: &MetricAttributes) {
382
408
  if let MetricAttributes::OTel { kvs } = attributes {
@@ -68,6 +68,12 @@ pub struct OtelCollectorOptions {
68
68
  /// If set to true, use f64 seconds for durations instead of u64 milliseconds
69
69
  #[builder(default)]
70
70
  pub use_seconds_for_durations: bool,
71
+ /// Overrides for histogram buckets. Units depend on the value of `use_seconds_for_durations`.
72
+ #[builder(default)]
73
+ pub histogram_bucket_overrides: HistogramBucketOverrides,
74
+ /// Protocol to use for communication with the collector
75
+ #[builder(default = "OtlpProtocol::Grpc")]
76
+ pub protocol: OtlpProtocol,
71
77
  }
72
78
 
73
79
  /// Options for exporting metrics to Prometheus
@@ -78,15 +84,33 @@ pub struct PrometheusExporterOptions {
78
84
  #[builder(default)]
79
85
  pub global_tags: HashMap<String, String>,
80
86
  /// If set true, all counters will include a "_total" suffix
81
- #[builder(default = "false")]
87
+ #[builder(default)]
82
88
  pub counters_total_suffix: bool,
83
89
  /// If set true, all histograms will include the unit in their name as a suffix.
84
90
  /// Ex: "_milliseconds".
85
- #[builder(default = "false")]
91
+ #[builder(default)]
86
92
  pub unit_suffix: bool,
87
93
  /// If set to true, use f64 seconds for durations instead of u64 milliseconds
88
94
  #[builder(default)]
89
95
  pub use_seconds_for_durations: bool,
96
+ /// Overrides for histogram buckets. Units depend on the value of `use_seconds_for_durations`.
97
+ #[builder(default)]
98
+ pub histogram_bucket_overrides: HistogramBucketOverrides,
99
+ }
100
+
101
+ /// Allows overriding the buckets used by histogram metrics
102
+ #[derive(Debug, Clone, Default)]
103
+ pub struct HistogramBucketOverrides {
104
+ /// Overrides where the key is the metric name and the value is the list of bucket boundaries.
105
+ /// The metric name will apply regardless of name prefixing, if any. IE: the name acts like
106
+ /// `*metric_name`.
107
+ ///
108
+ /// The string names of core's built-in histogram metrics are publicly available on the
109
+ /// `core::telemetry` module and the `client` crate.
110
+ ///
111
+ /// See [here](https://docs.rs/opentelemetry_sdk/latest/opentelemetry_sdk/metrics/enum.Aggregation.html#variant.ExplicitBucketHistogram.field.boundaries)
112
+ /// for the exact meaning of boundaries.
113
+ pub overrides: HashMap<String, Vec<f64>>,
90
114
  }
91
115
 
92
116
  /// Control where logs go
@@ -102,7 +126,8 @@ pub enum Logger {
102
126
  /// An [EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html) filter string.
103
127
  filter: String,
104
128
  },
105
- // Push logs to Lang. Can used with temporal_sdk_core::telemetry::CoreLogBufferedConsumer to buffer.
129
+ /// Push logs to Lang. Can be used with
130
+ /// temporal_sdk_core::telemetry::log_export::CoreLogBufferedConsumer to buffer.
106
131
  Push {
107
132
  /// An [EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html) filter string.
108
133
  filter: String,
@@ -121,6 +146,15 @@ pub enum MetricTemporality {
121
146
  Delta,
122
147
  }
123
148
 
149
+ /// Options for configuring telemetry
150
+ #[derive(Debug, Clone, Copy)]
151
+ pub enum OtlpProtocol {
152
+ /// Use gRPC to communicate with the collector
153
+ Grpc,
154
+ /// Use HTTP to communicate with the collector
155
+ Http,
156
+ }
157
+
124
158
  impl Default for TelemetryOptions {
125
159
  fn default() -> Self {
126
160
  TelemetryOptionsBuilder::default().build().unwrap()
@@ -6,7 +6,7 @@ use std::{
6
6
  time::Duration,
7
7
  };
8
8
  use temporal_sdk_core_protos::coresdk::{
9
- ActivitySlotInfo, LocalActivitySlotInfo, WorkflowSlotInfo,
9
+ ActivitySlotInfo, LocalActivitySlotInfo, NexusSlotInfo, WorkflowSlotInfo,
10
10
  };
11
11
 
12
12
  const MAX_CONCURRENT_WFT_POLLS_DEFAULT: usize = 5;
@@ -56,6 +56,10 @@ pub struct WorkerConfig {
56
56
  /// worker's task queue
57
57
  #[builder(default = "5")]
58
58
  pub max_concurrent_at_polls: usize,
59
+ /// Maximum number of concurrent poll nexus task requests we will perform at a time on this
60
+ /// worker's task queue
61
+ #[builder(default = "5")]
62
+ pub max_concurrent_nexus_polls: usize,
59
63
  /// If set to true this worker will only handle workflow tasks and local activities, it will not
60
64
  /// poll for activity tasks.
61
65
  #[builder(default = "false")]
@@ -80,6 +84,8 @@ pub struct WorkerConfig {
80
84
  /// server-side. Note that this only takes effect upon an activity poll request. If multiple
81
85
  /// workers on the same queue have different values set, they will thrash with the last poller
82
86
  /// winning.
87
+ ///
88
+ /// Setting this to a nonzero value will also disable eager activity execution.
83
89
  #[builder(default)]
84
90
  pub max_task_queue_activities_per_second: Option<f64>,
85
91
 
@@ -112,8 +118,8 @@ pub struct WorkerConfig {
112
118
  #[builder(default = "5")]
113
119
  pub fetching_concurrency: usize,
114
120
 
115
- /// If set, core will issue cancels for all outstanding activities after shutdown has been
116
- /// initiated and this amount of time has elapsed.
121
+ /// If set, core will issue cancels for all outstanding activities and nexus operations after
122
+ /// shutdown has been initiated and this amount of time has elapsed.
117
123
  #[builder(default)]
118
124
  pub graceful_shutdown_period: Option<Duration>,
119
125
 
@@ -151,6 +157,12 @@ pub struct WorkerConfig {
151
157
  /// Mutually exclusive with `tuner`
152
158
  #[builder(setter(into, strip_option), default)]
153
159
  pub max_outstanding_local_activities: Option<usize>,
160
+ /// The maximum number of nexus tasks that will ever be given to this worker
161
+ /// concurrently
162
+ ///
163
+ /// Mutually exclusive with `tuner`
164
+ #[builder(setter(into, strip_option), default)]
165
+ pub max_outstanding_nexus_tasks: Option<usize>,
154
166
  }
155
167
 
156
168
  impl WorkerConfig {
@@ -261,6 +273,11 @@ pub trait WorkerTuner {
261
273
  &self,
262
274
  ) -> Arc<dyn SlotSupplier<SlotKind = LocalActivitySlotKind> + Send + Sync>;
263
275
 
276
+ /// Return a [SlotSupplier] for nexus tasks
277
+ fn nexus_task_slot_supplier(
278
+ &self,
279
+ ) -> Arc<dyn SlotSupplier<SlotKind = NexusSlotKind> + Send + Sync>;
280
+
264
281
  /// Core will call this at worker initialization time, allowing the implementation to hook up to
265
282
  /// metrics if any are configured. If not, it will not be called.
266
283
  fn attach_metrics(&self, metrics: TemporalMeter);
@@ -362,6 +379,7 @@ pub enum SlotKindType {
362
379
  Workflow,
363
380
  Activity,
364
381
  LocalActivity,
382
+ Nexus,
365
383
  }
366
384
 
367
385
  #[derive(Debug, Copy, Clone)]
@@ -370,11 +388,14 @@ pub struct WorkflowSlotKind {}
370
388
  pub struct ActivitySlotKind {}
371
389
  #[derive(Debug, Copy, Clone)]
372
390
  pub struct LocalActivitySlotKind {}
391
+ #[derive(Debug, Copy, Clone)]
392
+ pub struct NexusSlotKind {}
373
393
 
374
394
  pub enum SlotInfo<'a> {
375
395
  Workflow(&'a WorkflowSlotInfo),
376
396
  Activity(&'a ActivitySlotInfo),
377
397
  LocalActivity(&'a LocalActivitySlotInfo),
398
+ Nexus(&'a NexusSlotInfo),
378
399
  }
379
400
 
380
401
  pub trait SlotInfoTrait: prost::Message {
@@ -395,6 +416,11 @@ impl SlotInfoTrait for LocalActivitySlotInfo {
395
416
  SlotInfo::LocalActivity(self)
396
417
  }
397
418
  }
419
+ impl SlotInfoTrait for NexusSlotInfo {
420
+ fn downcast(&self) -> SlotInfo {
421
+ SlotInfo::Nexus(self)
422
+ }
423
+ }
398
424
 
399
425
  pub trait SlotKind {
400
426
  type Info: SlotInfoTrait;
@@ -422,3 +448,10 @@ impl SlotKind for LocalActivitySlotKind {
422
448
  SlotKindType::LocalActivity
423
449
  }
424
450
  }
451
+ impl SlotKind for NexusSlotKind {
452
+ type Info = NexusSlotInfo;
453
+
454
+ fn kind() -> SlotKindType {
455
+ SlotKindType::Nexus
456
+ }
457
+ }
@@ -0,0 +1,25 @@
1
+ version: '3.5'
2
+
3
+ services:
4
+ otel-collector:
5
+ image: otel/opentelemetry-collector:latest
6
+ command: [ '--config=/etc/otel-collector-ci.yaml' ]
7
+ volumes:
8
+ - ../etc/otel-collector-ci.yaml:/etc/otel-collector-ci.yaml
9
+ ports:
10
+ # - "1888:1888" # pprof extension
11
+ # It's useful to be able to manually inspect metrics during dev
12
+ - '8888:8888' # Prometheus metrics exposed by the collector
13
+ - '8889:8889' # Prometheus exporter metrics
14
+ # - "13133:13133" # health_check extension
15
+ - '4317:4317' # OTLP gRPC receiver
16
+ - '4318:4318' # OTLP HTTP receiver
17
+ # - "55679:55679" # zpages extension
18
+
19
+ prometheus:
20
+ container_name: prometheus
21
+ image: prom/prometheus:latest
22
+ volumes:
23
+ - ../etc/prometheus.yaml:/etc/prometheus/prometheus.yml
24
+ ports:
25
+ - '9090:9090'