temporalio 0.0.2 → 0.1.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.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -23
  3. data/bridge/Cargo.lock +168 -59
  4. data/bridge/Cargo.toml +4 -2
  5. data/bridge/sdk-core/README.md +19 -6
  6. data/bridge/sdk-core/client/src/lib.rs +215 -39
  7. data/bridge/sdk-core/client/src/metrics.rs +17 -8
  8. data/bridge/sdk-core/client/src/raw.rs +4 -4
  9. data/bridge/sdk-core/client/src/retry.rs +32 -20
  10. data/bridge/sdk-core/core/Cargo.toml +22 -9
  11. data/bridge/sdk-core/core/src/abstractions.rs +203 -14
  12. data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
  13. data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
  14. data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
  15. data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
  16. data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
  17. data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
  18. data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
  19. data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
  20. data/bridge/sdk-core/core/src/lib.rs +16 -9
  21. data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
  22. data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
  23. data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
  24. data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
  25. data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
  26. data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
  27. data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  28. data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
  29. data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
  30. data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
  31. data/bridge/sdk-core/core/src/worker/client.rs +18 -2
  32. data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
  33. data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  34. data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  35. data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
  36. data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
  37. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
  38. data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
  39. data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
  40. data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
  41. data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
  42. data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
  43. data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
  44. data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
  45. data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
  46. data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
  47. data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
  48. data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
  49. data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  50. data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
  51. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
  52. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
  53. data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
  54. data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
  55. data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
  56. data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
  57. data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  58. data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
  59. data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  60. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  61. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  62. data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
  63. data/bridge/sdk-core/core-api/Cargo.toml +2 -1
  64. data/bridge/sdk-core/core-api/src/errors.rs +1 -34
  65. data/bridge/sdk-core/core-api/src/lib.rs +6 -2
  66. data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
  67. data/bridge/sdk-core/core-api/src/worker.rs +14 -1
  68. data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
  69. data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
  70. data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  71. data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
  72. data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
  73. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
  74. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
  75. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
  76. data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
  77. data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
  78. data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
  79. data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
  80. data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
  81. data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  82. data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
  83. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
  84. data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
  85. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
  86. data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
  87. data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
  88. data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  89. data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  90. data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
  91. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
  92. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
  93. data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
  94. data/bridge/sdk-core/sdk/Cargo.toml +3 -2
  95. data/bridge/sdk-core/sdk/src/lib.rs +87 -20
  96. data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
  97. data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  98. data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
  99. data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
  100. data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
  101. data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
  102. data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  103. data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
  104. data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
  105. data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
  106. data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
  107. data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  108. data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
  109. data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
  110. data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  111. data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  112. data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
  113. data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  114. data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  115. data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  116. data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  117. data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
  118. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  119. data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  120. data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
  121. data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  122. data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  123. data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
  124. data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
  125. data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
  126. data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
  127. data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  128. data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  129. data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  130. data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  131. data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
  132. data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
  133. data/bridge/sdk-core/tests/main.rs +3 -13
  134. data/bridge/sdk-core/tests/runner.rs +75 -36
  135. data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
  136. data/bridge/src/connection.rs +41 -25
  137. data/bridge/src/lib.rs +269 -14
  138. data/bridge/src/runtime.rs +1 -1
  139. data/bridge/src/test_server.rs +153 -0
  140. data/bridge/src/worker.rs +89 -16
  141. data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
  142. data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
  143. data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
  144. data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
  145. data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
  146. data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
  147. data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
  148. data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
  149. data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
  150. data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
  151. data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
  152. data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
  153. data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
  154. data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
  155. data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
  156. data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
  157. data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
  158. data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
  159. data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
  160. data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
  161. data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
  162. data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
  163. data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
  164. data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
  165. data/lib/temporalio/activity/context.rb +13 -8
  166. data/lib/temporalio/activity/info.rb +1 -1
  167. data/lib/temporalio/bridge/connect_options.rb +15 -0
  168. data/lib/temporalio/bridge/retry_config.rb +24 -0
  169. data/lib/temporalio/bridge/tls_options.rb +19 -0
  170. data/lib/temporalio/client/implementation.rb +8 -8
  171. data/lib/temporalio/connection/retry_config.rb +44 -0
  172. data/lib/temporalio/connection/service.rb +20 -0
  173. data/lib/temporalio/connection/test_service.rb +92 -0
  174. data/lib/temporalio/connection/tls_options.rb +51 -0
  175. data/lib/temporalio/connection/workflow_service.rb +731 -0
  176. data/lib/temporalio/connection.rb +55 -720
  177. data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
  178. data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
  179. data/lib/temporalio/interceptor/chain.rb +5 -5
  180. data/lib/temporalio/interceptor/client.rb +8 -4
  181. data/lib/temporalio/interceptor.rb +22 -0
  182. data/lib/temporalio/retry_policy.rb +13 -3
  183. data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
  184. data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
  185. data/lib/temporalio/testing/workflow_environment.rb +112 -0
  186. data/lib/temporalio/testing.rb +175 -0
  187. data/lib/temporalio/version.rb +1 -1
  188. data/lib/temporalio/worker/activity_runner.rb +26 -4
  189. data/lib/temporalio/worker/activity_worker.rb +44 -18
  190. data/lib/temporalio/worker/sync_worker.rb +47 -11
  191. data/lib/temporalio/worker.rb +27 -21
  192. data/lib/temporalio/workflow/async.rb +46 -0
  193. data/lib/temporalio/workflow/future.rb +138 -0
  194. data/lib/temporalio/workflow/info.rb +76 -0
  195. data/temporalio.gemspec +4 -3
  196. metadata +67 -17
  197. data/bridge/sdk-core/Cargo.lock +0 -2606
  198. data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
  199. data/lib/bridge.so +0 -0
  200. data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
  201. data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
  202. data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
@@ -23,6 +23,9 @@ use std::os::unix::fs::OpenOptionsExt;
23
23
  use std::process::Stdio;
24
24
 
25
25
  /// Configuration for Temporalite.
26
+ /// Will be removed eventually as its successor, Temporal CLI matures.
27
+ /// We don't care for the duplication between this struct and [TemporalDevServerConfig] and prefer that over another
28
+ /// abstraction since the existence of this struct is temporary.
26
29
  #[derive(Debug, Clone, derive_builder::Builder)]
27
30
  pub struct TemporaliteConfig {
28
31
  /// Required path to executable or download info.
@@ -59,7 +62,10 @@ impl TemporaliteConfig {
59
62
  /// Start a Temporalite server with configurable stdout destination.
60
63
  pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
61
64
  // Get exe path
62
- let exe_path = self.exe.get_or_download("temporalite").await?;
65
+ let exe_path = self
66
+ .exe
67
+ .get_or_download("temporalite", "temporalite")
68
+ .await?;
63
69
 
64
70
  // Get free port if not already given
65
71
  let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
@@ -77,6 +83,8 @@ impl TemporaliteConfig {
77
83
  self.log.0.clone(),
78
84
  "--log-level".to_owned(),
79
85
  self.log.1.clone(),
86
+ "--dynamic-config-value".to_owned(),
87
+ "frontend.enableServerVersionCheck=false".to_owned(),
80
88
  ];
81
89
  if let Some(db_filename) = &self.db_filename {
82
90
  args.push("--filename".to_owned());
@@ -101,6 +109,86 @@ impl TemporaliteConfig {
101
109
  }
102
110
  }
103
111
 
112
+ /// Configuration for Temporal CLI dev server.
113
+ #[derive(Debug, Clone, derive_builder::Builder)]
114
+ pub struct TemporalDevServerConfig {
115
+ /// Required path to executable or download info.
116
+ pub exe: EphemeralExe,
117
+ /// Namespace to use.
118
+ #[builder(default = "\"default\".to_owned()")]
119
+ pub namespace: String,
120
+ /// IP to bind to.
121
+ #[builder(default = "\"127.0.0.1\".to_owned()")]
122
+ pub ip: String,
123
+ /// Port to use or obtains a free one if none given.
124
+ #[builder(default)]
125
+ pub port: Option<u16>,
126
+ /// Sqlite DB filename if persisting or non-persistent if none.
127
+ #[builder(default)]
128
+ pub db_filename: Option<String>,
129
+ /// Whether to enable the UI.
130
+ #[builder(default)]
131
+ pub ui: bool,
132
+ /// Log format and level
133
+ #[builder(default = "(\"pretty\".to_owned(), \"warn\".to_owned())")]
134
+ pub log: (String, String),
135
+ /// Additional arguments to Temporalite.
136
+ #[builder(default)]
137
+ pub extra_args: Vec<String>,
138
+ }
139
+
140
+ impl TemporalDevServerConfig {
141
+ /// Start a Temporal CLI dev server.
142
+ pub async fn start_server(&self) -> anyhow::Result<EphemeralServer> {
143
+ self.start_server_with_output(Stdio::inherit()).await
144
+ }
145
+
146
+ /// Start a Temporal CLI dev server with configurable stdout destination.
147
+ pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
148
+ // Get exe path
149
+ let exe_path = self.exe.get_or_download("cli", "temporal").await?;
150
+
151
+ // Get free port if not already given
152
+ let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
153
+
154
+ // Build arg set
155
+ let mut args = vec![
156
+ "server".to_owned(),
157
+ "start-dev".to_owned(),
158
+ "--port".to_owned(),
159
+ port.to_string(),
160
+ "--namespace".to_owned(),
161
+ self.namespace.clone(),
162
+ "--ip".to_owned(),
163
+ self.ip.clone(),
164
+ "--log-format".to_owned(),
165
+ self.log.0.clone(),
166
+ "--log-level".to_owned(),
167
+ self.log.1.clone(),
168
+ "--dynamic-config-value".to_owned(),
169
+ "frontend.enableServerVersionCheck=false".to_owned(),
170
+ ];
171
+ if let Some(db_filename) = &self.db_filename {
172
+ args.push("--filename".to_owned());
173
+ args.push(db_filename.clone());
174
+ }
175
+ if !self.ui {
176
+ args.push("--headless".to_owned());
177
+ }
178
+ args.extend(self.extra_args.clone());
179
+
180
+ // Start
181
+ EphemeralServer::start(EphemeralServerConfig {
182
+ exe_path,
183
+ port,
184
+ args,
185
+ has_test_service: false,
186
+ output,
187
+ })
188
+ .await
189
+ }
190
+ }
191
+
104
192
  /// Configuration for the test server.
105
193
  #[derive(Debug, Clone, derive_builder::Builder)]
106
194
  pub struct TestServerConfig {
@@ -123,7 +211,10 @@ impl TestServerConfig {
123
211
  /// Start a test server with configurable stdout.
124
212
  pub async fn start_server_with_output(&self, output: Stdio) -> anyhow::Result<EphemeralServer> {
125
213
  // Get exe path
126
- let exe_path = self.exe.get_or_download("temporal-test-server").await?;
214
+ let exe_path = self
215
+ .exe
216
+ .get_or_download("temporal-test-server", "temporal-test-server")
217
+ .await?;
127
218
 
128
219
  // Get free port if not already given
129
220
  let port = self.port.unwrap_or_else(|| get_free_port("0.0.0.0"));
@@ -172,7 +263,7 @@ impl EphemeralServer {
172
263
  .stdout(config.output)
173
264
  .spawn()?;
174
265
  let target = format!("127.0.0.1:{}", config.port);
175
- let target_url = format!("http://{}", target);
266
+ let target_url = format!("http://{target}");
176
267
  let success = Ok(EphemeralServer {
177
268
  target,
178
269
  has_test_service: config.has_test_service,
@@ -262,7 +353,7 @@ pub enum EphemeralExe {
262
353
  #[derive(Debug, Clone)]
263
354
  pub enum EphemeralExeVersion {
264
355
  /// Use a default version for the given SDK name and version.
265
- Default {
356
+ SDKDefault {
266
357
  /// Name of the SDK to get the default for.
267
358
  sdk_name: String,
268
359
  /// Version of the SDK to get the default for.
@@ -280,7 +371,11 @@ struct DownloadInfo {
280
371
  }
281
372
 
282
373
  impl EphemeralExe {
283
- async fn get_or_download(&self, artifact_name: &str) -> anyhow::Result<PathBuf> {
374
+ async fn get_or_download(
375
+ &self,
376
+ artifact_name: &str,
377
+ downloaded_name_prefix: &str,
378
+ ) -> anyhow::Result<PathBuf> {
284
379
  match self {
285
380
  EphemeralExe::ExistingPath(exe_path) => {
286
381
  let path = PathBuf::from(exe_path);
@@ -301,12 +396,12 @@ impl EphemeralExe {
301
396
  };
302
397
  // Create dest file based on SDK name/version or fixed version
303
398
  let dest = dest_dir.join(match version {
304
- EphemeralExeVersion::Default {
399
+ EphemeralExeVersion::SDKDefault {
305
400
  sdk_name,
306
401
  sdk_version,
307
- } => format!("{}-{}-{}{}", artifact_name, sdk_name, sdk_version, out_ext),
402
+ } => format!("{downloaded_name_prefix}-{sdk_name}-{sdk_version}{out_ext}"),
308
403
  EphemeralExeVersion::Fixed(version) => {
309
- format!("{}-{}{}", artifact_name, version, out_ext)
404
+ format!("{downloaded_name_prefix}-{version}{out_ext}")
310
405
  }
311
406
  });
312
407
  debug!(
@@ -327,7 +422,7 @@ impl EphemeralExe {
327
422
  };
328
423
  let mut get_info_params = vec![("arch", arch), ("platform", platform)];
329
424
  let version_name = match version {
330
- EphemeralExeVersion::Default {
425
+ EphemeralExeVersion::SDKDefault {
331
426
  sdk_name,
332
427
  sdk_version,
333
428
  } => {
@@ -340,8 +435,7 @@ impl EphemeralExe {
340
435
  let client = reqwest::Client::new();
341
436
  let info: DownloadInfo = client
342
437
  .get(format!(
343
- "https://temporal.download/{}/{}",
344
- artifact_name, version_name
438
+ "https://temporal.download/{artifact_name}/{version_name}"
345
439
  ))
346
440
  .query(&get_info_params)
347
441
  .send()
@@ -371,7 +465,7 @@ impl EphemeralExe {
371
465
  fn get_free_port(bind_ip: &str) -> u16 {
372
466
  // Can just ask OS to give us a port then close socket. OS's don't give that
373
467
  // port back to anyone else anytime soon.
374
- std::net::TcpListener::bind(format!("{}:0", bind_ip))
468
+ std::net::TcpListener::bind(format!("{bind_ip}:0"))
375
469
  .unwrap()
376
470
  .local_addr()
377
471
  .unwrap()
@@ -0,0 +1,136 @@
1
+ //! Utilities for and tracking of internal versions which alter history in incompatible ways
2
+ //! so that we can use older code paths for workflows executed on older core versions.
3
+
4
+ use std::collections::{BTreeSet, HashSet};
5
+ use temporal_sdk_core_protos::temporal::api::{
6
+ history::v1::WorkflowTaskCompletedEventAttributes, sdk::v1::WorkflowTaskCompletedMetadata,
7
+ workflowservice::v1::get_system_info_response,
8
+ };
9
+
10
+ /// This enumeration contains internal flags that may result in incompatible history changes with
11
+ /// older workflows, or other breaking changes.
12
+ ///
13
+ /// When a flag has existed long enough the version it was introduced in is no longer supported, it
14
+ /// may be removed from the enum. *Importantly*, all variants must be given explicit values, such
15
+ /// that removing older variants does not create any change in existing values. Removed flag
16
+ /// variants must be reserved forever (a-la protobuf), and should be called out in a comment.
17
+ #[repr(u32)]
18
+ #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
19
+ pub(crate) enum CoreInternalFlags {
20
+ /// In this flag, additional checks were added to a number of state machines to ensure that
21
+ /// the ID and type of activities, local activities, and child workflows match during replay.
22
+ IdAndTypeDeterminismChecks = 1,
23
+ /// We received a value higher than this code can understand.
24
+ TooHigh = u32::MAX,
25
+ }
26
+
27
+ #[derive(Debug, Clone, PartialEq, Eq)]
28
+ pub(crate) struct InternalFlags {
29
+ enabled: bool,
30
+ core: BTreeSet<CoreInternalFlags>,
31
+ lang: BTreeSet<u32>,
32
+ core_since_last_complete: HashSet<CoreInternalFlags>,
33
+ lang_since_last_complete: HashSet<u32>,
34
+ }
35
+
36
+ impl InternalFlags {
37
+ pub fn new(server_capabilities: &get_system_info_response::Capabilities) -> Self {
38
+ Self {
39
+ enabled: server_capabilities.sdk_metadata,
40
+ core: Default::default(),
41
+ lang: Default::default(),
42
+ core_since_last_complete: Default::default(),
43
+ lang_since_last_complete: Default::default(),
44
+ }
45
+ }
46
+
47
+ pub fn add_from_complete(&mut self, e: &WorkflowTaskCompletedEventAttributes) {
48
+ if !self.enabled {
49
+ return;
50
+ }
51
+
52
+ if let Some(metadata) = e.sdk_metadata.as_ref() {
53
+ self.core.extend(
54
+ metadata
55
+ .core_used_flags
56
+ .iter()
57
+ .map(|u| CoreInternalFlags::from_u32(*u)),
58
+ );
59
+ self.lang.extend(metadata.lang_used_flags.iter());
60
+ }
61
+ }
62
+
63
+ pub fn add_lang_used(&mut self, flags: impl IntoIterator<Item = u32>) {
64
+ if !self.enabled {
65
+ return;
66
+ }
67
+
68
+ self.lang_since_last_complete.extend(flags.into_iter());
69
+ }
70
+
71
+ /// Returns true if this flag may currently be used. If `should_record` is true, always returns
72
+ /// true and records the flag as being used, for taking later via
73
+ /// [Self::gather_for_wft_complete].
74
+ pub fn try_use(&mut self, core_patch: CoreInternalFlags, should_record: bool) -> bool {
75
+ if !self.enabled {
76
+ // If the server does not support the metadata field, we must assume
77
+ return false;
78
+ }
79
+
80
+ if should_record {
81
+ self.core_since_last_complete.insert(core_patch);
82
+ true
83
+ } else {
84
+ self.core.contains(&core_patch)
85
+ }
86
+ }
87
+
88
+ /// Wipes the recorded flags used during the current WFT and returns a partially filled
89
+ /// sdk metadata message that can be combined with any existing data before sending the WFT
90
+ /// complete
91
+ pub fn gather_for_wft_complete(&mut self) -> WorkflowTaskCompletedMetadata {
92
+ WorkflowTaskCompletedMetadata {
93
+ core_used_flags: self
94
+ .core_since_last_complete
95
+ .drain()
96
+ .map(|p| p as u32)
97
+ .collect(),
98
+ lang_used_flags: self.lang_since_last_complete.drain().collect(),
99
+ }
100
+ }
101
+
102
+ pub fn all_lang(&self) -> &BTreeSet<u32> {
103
+ &self.lang
104
+ }
105
+ }
106
+
107
+ impl CoreInternalFlags {
108
+ fn from_u32(v: u32) -> Self {
109
+ match v {
110
+ 1 => Self::IdAndTypeDeterminismChecks,
111
+ _ => Self::TooHigh,
112
+ }
113
+ }
114
+ }
115
+
116
+ #[cfg(test)]
117
+ mod tests {
118
+ use super::*;
119
+ use temporal_sdk_core_protos::temporal::api::workflowservice::v1::get_system_info_response::Capabilities;
120
+
121
+ #[test]
122
+ fn disabled_in_capabilities_disables() {
123
+ let mut f = InternalFlags::new(&Capabilities::default());
124
+ f.add_lang_used([1]);
125
+ f.add_from_complete(&WorkflowTaskCompletedEventAttributes {
126
+ sdk_metadata: Some(WorkflowTaskCompletedMetadata {
127
+ core_used_flags: vec![1],
128
+ lang_used_flags: vec![],
129
+ }),
130
+ ..Default::default()
131
+ });
132
+ let gathered = f.gather_for_wft_complete();
133
+ assert_matches!(gathered.core_used_flags.as_slice(), &[]);
134
+ assert_matches!(gathered.lang_used_flags.as_slice(), &[]);
135
+ }
136
+ }
@@ -13,6 +13,7 @@ extern crate core;
13
13
 
14
14
  mod abstractions;
15
15
  pub mod ephemeral_server;
16
+ mod internal_flags;
16
17
  mod pollers;
17
18
  mod protosext;
18
19
  pub mod replay;
@@ -36,13 +37,16 @@ pub use temporal_sdk_core_api as api;
36
37
  pub use temporal_sdk_core_protos as protos;
37
38
  pub use temporal_sdk_core_protos::TaskToken;
38
39
  pub use url::Url;
40
+ #[cfg(feature = "save_wf_inputs")]
41
+ pub use worker::replay_wf_state_inputs;
39
42
  pub use worker::{Worker, WorkerConfig, WorkerConfigBuilder};
40
43
 
41
44
  use crate::{
42
45
  replay::{mock_client_from_histories, Historator, HistoryForReplay},
43
46
  telemetry::{
44
- metrics::MetricsContext, remove_trace_subscriber_for_current_thread,
45
- set_trace_subscriber_for_current_thread, telemetry_init, TelemetryInstance,
47
+ metrics::{MetricsContext, TemporalMeter},
48
+ remove_trace_subscriber_for_current_thread, set_trace_subscriber_for_current_thread,
49
+ telemetry_init, TelemetryInstance,
46
50
  },
47
51
  worker::client::WorkerClientBag,
48
52
  };
@@ -51,7 +55,7 @@ use std::sync::Arc;
51
55
  use temporal_client::{ConfiguredClient, TemporalServiceClientWithMetrics};
52
56
  use temporal_sdk_core_api::{
53
57
  errors::{CompleteActivityError, PollActivityError, PollWfError},
54
- telemetry::{CoreTelemetry, TelemetryOptions},
58
+ telemetry::TelemetryOptions,
55
59
  Worker as WorkerTrait,
56
60
  };
57
61
  use temporal_sdk_core_protos::coresdk::ActivityHeartbeat;
@@ -62,7 +66,7 @@ use temporal_sdk_core_protos::coresdk::ActivityHeartbeat;
62
66
  /// After the worker is initialized, you should use [CoreRuntime::tokio_handle] to run the worker's
63
67
  /// async functions.
64
68
  ///
65
- /// Lang implementations may pass in a [temporal_client::ConfiguredClient] directly (or a
69
+ /// Lang implementations may pass in a [ConfiguredClient] directly (or a
66
70
  /// [RetryClient] wrapping one, or a handful of other variants of the same idea). When they do so,
67
71
  /// this function will always overwrite the client retry configuration, force the client to use the
68
72
  /// namespace defined in the worker config, and set the client identity appropriately. IE: Use
@@ -97,9 +101,12 @@ where
97
101
  worker_config.use_worker_versioning,
98
102
  ));
99
103
 
100
- let metrics = MetricsContext::top_level(worker_config.namespace.clone(), &runtime.telemetry)
101
- .with_task_q(worker_config.task_queue.clone());
102
- Ok(Worker::new(worker_config, sticky_q, client_bag, metrics))
104
+ Ok(Worker::new(
105
+ worker_config,
106
+ sticky_q,
107
+ client_bag,
108
+ Some(&runtime.telemetry),
109
+ ))
103
110
  }
104
111
 
105
112
  /// Create a worker for replaying a specific history. It will auto-shutdown as soon as the history
@@ -126,7 +133,7 @@ where
126
133
  let post_activate = historator.get_post_activate_hook();
127
134
  let shutdown_tok = historator.get_shutdown_setter();
128
135
  let client = mock_client_from_histories(historator);
129
- let mut worker = Worker::new(config, None, Arc::new(client), MetricsContext::no_op());
136
+ let mut worker = Worker::new(config, None, Arc::new(client), None);
130
137
  worker.set_post_activate_hook(post_activate);
131
138
  shutdown_tok(worker.shutdown_token());
132
139
  Ok(worker)
@@ -258,7 +265,7 @@ impl CoreRuntime {
258
265
  }
259
266
 
260
267
  /// Returns the metric meter used for recording metrics, if they were enabled.
261
- pub fn metric_meter(&self) -> Option<&opentelemetry::metrics::Meter> {
268
+ pub fn metric_meter(&self) -> Option<TemporalMeter> {
262
269
  self.telemetry.get_metric_meter()
263
270
  }
264
271
 
@@ -139,7 +139,7 @@ impl<'a> tracing::field::Visit for JsonVisitor<'a> {
139
139
  fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
140
140
  self.0.insert(
141
141
  field.name().to_string(),
142
- serde_json::json!(format!("{:?}", value)),
142
+ serde_json::json!(format!("{value:?}")),
143
143
  );
144
144
  }
145
145
  }
@@ -10,8 +10,8 @@ use opentelemetry::{
10
10
  },
11
11
  Context, KeyValue,
12
12
  };
13
- use std::{sync::Arc, time::Duration};
14
- use temporal_sdk_core_api::telemetry::CoreTelemetry;
13
+ use std::{ops::Deref, sync::Arc, time::Duration};
14
+ use temporal_client::ClientMetricProvider;
15
15
 
16
16
  /// Used to track context associated with metrics, and record/update them
17
17
  ///
@@ -24,6 +24,46 @@ pub(crate) struct MetricsContext {
24
24
  instruments: Arc<Instruments>,
25
25
  }
26
26
 
27
+ /// Wraps OTel's [Meter] to ensure we name our metrics properly, or any other temporal-specific
28
+ /// metrics customizations
29
+ #[derive(derive_more::Constructor)]
30
+ pub struct TemporalMeter<'a> {
31
+ inner: &'a Meter,
32
+ metrics_prefix: &'static str,
33
+ }
34
+
35
+ impl<'a> TemporalMeter<'a> {
36
+ pub(crate) fn counter(&self, name: &'static str) -> Counter<u64> {
37
+ self.inner
38
+ .u64_counter(self.metrics_prefix.to_string() + name)
39
+ .init()
40
+ }
41
+
42
+ pub(crate) fn histogram(&self, name: &'static str) -> Histogram<u64> {
43
+ self.inner
44
+ .u64_histogram(self.metrics_prefix.to_string() + name)
45
+ .init()
46
+ }
47
+ }
48
+
49
+ impl<'a> ClientMetricProvider for TemporalMeter<'a> {
50
+ fn counter(&self, name: &'static str) -> Counter<u64> {
51
+ self.counter(name)
52
+ }
53
+
54
+ fn histogram(&self, name: &'static str) -> Histogram<u64> {
55
+ self.histogram(name)
56
+ }
57
+ }
58
+
59
+ impl<'a> Deref for TemporalMeter<'a> {
60
+ type Target = dyn ClientMetricProvider + 'a;
61
+
62
+ fn deref(&self) -> &Self::Target {
63
+ self as &Self::Target
64
+ }
65
+ }
66
+
27
67
  struct Instruments {
28
68
  wf_completed_counter: Counter<u64>,
29
69
  wf_canceled_counter: Counter<u64>,
@@ -54,10 +94,10 @@ impl MetricsContext {
54
94
  Self {
55
95
  ctx: Default::default(),
56
96
  kvs: Default::default(),
57
- instruments: Arc::new(Instruments::new_explicit(
97
+ instruments: Arc::new(Instruments::new_explicit(TemporalMeter::new(
58
98
  &NoopMeterProvider::new().meter("fakemeter"),
59
99
  "fakemetrics",
60
- )),
100
+ ))),
61
101
  }
62
102
  }
63
103
 
@@ -257,42 +297,36 @@ impl Instruments {
257
297
  meter
258
298
  } else {
259
299
  no_op_meter = NoopMeterProvider::default().meter("no_op");
260
- &no_op_meter
300
+ TemporalMeter::new(&no_op_meter, "fakemetrics")
261
301
  };
262
- Self::new_explicit(meter, telem.metric_prefix)
302
+ Self::new_explicit(meter)
263
303
  }
264
304
 
265
- fn new_explicit(meter: &Meter, metric_prefix: &'static str) -> Self {
266
- let ctr = |name: &'static str| -> Counter<u64> {
267
- meter.u64_counter(metric_prefix.to_string() + name).init()
268
- };
269
- let hst = |name: &'static str| -> Histogram<u64> {
270
- meter.u64_histogram(metric_prefix.to_string() + name).init()
271
- };
305
+ fn new_explicit(meter: TemporalMeter) -> Self {
272
306
  Self {
273
- wf_completed_counter: ctr("workflow_completed"),
274
- wf_canceled_counter: ctr("workflow_canceled"),
275
- wf_failed_counter: ctr("workflow_failed"),
276
- wf_cont_counter: ctr("workflow_continue_as_new"),
277
- wf_e2e_latency: hst(WF_E2E_LATENCY_NAME),
278
- wf_task_queue_poll_empty_counter: ctr("workflow_task_queue_poll_empty"),
279
- wf_task_queue_poll_succeed_counter: ctr("workflow_task_queue_poll_succeed"),
280
- wf_task_execution_failure_counter: ctr("workflow_task_queue_poll_failed"),
281
- wf_task_sched_to_start_latency: hst(WF_TASK_SCHED_TO_START_LATENCY_NAME),
282
- wf_task_replay_latency: hst(WF_TASK_REPLAY_LATENCY_NAME),
283
- wf_task_execution_latency: hst(WF_TASK_EXECUTION_LATENCY_NAME),
284
- act_poll_no_task: ctr("activity_poll_no_task"),
285
- act_task_received_counter: ctr("activity_task_received"),
286
- act_execution_failed: ctr("activity_execution_failed"),
287
- act_sched_to_start_latency: hst(ACT_SCHED_TO_START_LATENCY_NAME),
288
- act_exec_latency: hst(ACT_EXEC_LATENCY_NAME),
307
+ wf_completed_counter: meter.counter("workflow_completed"),
308
+ wf_canceled_counter: meter.counter("workflow_canceled"),
309
+ wf_failed_counter: meter.counter("workflow_failed"),
310
+ wf_cont_counter: meter.counter("workflow_continue_as_new"),
311
+ wf_e2e_latency: meter.histogram(WF_E2E_LATENCY_NAME),
312
+ wf_task_queue_poll_empty_counter: meter.counter("workflow_task_queue_poll_empty"),
313
+ wf_task_queue_poll_succeed_counter: meter.counter("workflow_task_queue_poll_succeed"),
314
+ wf_task_execution_failure_counter: meter.counter("workflow_task_execution_failed"),
315
+ wf_task_sched_to_start_latency: meter.histogram(WF_TASK_SCHED_TO_START_LATENCY_NAME),
316
+ wf_task_replay_latency: meter.histogram(WF_TASK_REPLAY_LATENCY_NAME),
317
+ wf_task_execution_latency: meter.histogram(WF_TASK_EXECUTION_LATENCY_NAME),
318
+ act_poll_no_task: meter.counter("activity_poll_no_task"),
319
+ act_task_received_counter: meter.counter("activity_task_received"),
320
+ act_execution_failed: meter.counter("activity_execution_failed"),
321
+ act_sched_to_start_latency: meter.histogram(ACT_SCHED_TO_START_LATENCY_NAME),
322
+ act_exec_latency: meter.histogram(ACT_EXEC_LATENCY_NAME),
289
323
  // name kept as worker start for compat with old sdk / what users expect
290
- worker_registered: ctr("worker_start"),
291
- num_pollers: hst(NUM_POLLERS_NAME),
292
- task_slots_available: hst(TASK_SLOTS_AVAILABLE_NAME),
293
- sticky_cache_hit: ctr("sticky_cache_hit"),
294
- sticky_cache_miss: ctr("sticky_cache_miss"),
295
- sticky_cache_size: hst(STICKY_CACHE_SIZE_NAME),
324
+ worker_registered: meter.counter("worker_start"),
325
+ num_pollers: meter.histogram(NUM_POLLERS_NAME),
326
+ task_slots_available: meter.histogram(TASK_SLOTS_AVAILABLE_NAME),
327
+ sticky_cache_hit: meter.counter("sticky_cache_hit"),
328
+ sticky_cache_miss: meter.counter("sticky_cache_miss"),
329
+ sticky_cache_size: meter.histogram(STICKY_CACHE_SIZE_NAME),
296
330
  }
297
331
  }
298
332
  }
@@ -30,6 +30,7 @@ use std::{
30
30
  collections::VecDeque,
31
31
  convert::TryInto,
32
32
  env,
33
+ net::SocketAddr,
33
34
  sync::{
34
35
  atomic::{AtomicBool, Ordering},
35
36
  Arc,
@@ -47,12 +48,10 @@ use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Layer};
47
48
  const TELEM_SERVICE_NAME: &str = "temporal-core-sdk";
48
49
 
49
50
  /// Help you construct an [EnvFilter] compatible filter string which will forward all core module
50
- /// traces at `core_level` and all others (from 3rd party modules, etc) at `other_levl.
51
+ /// traces at `core_level` and all others (from 3rd party modules, etc) at `other_level`.
51
52
  pub fn construct_filter_string(core_level: Level, other_level: Level) -> String {
52
53
  format!(
53
- "{o},temporal_sdk_core={l},temporal_client={l},temporal_sdk={l}",
54
- o = other_level,
55
- l = core_level
54
+ "{other_level},temporal_sdk_core={core_level},temporal_client={core_level},temporal_sdk={core_level}"
56
55
  )
57
56
  }
58
57
 
@@ -62,6 +61,7 @@ pub struct TelemetryInstance {
62
61
  logs_out: Option<Mutex<CoreLogsOut>>,
63
62
  metrics: Option<(Box<dyn MeterProvider + Send + Sync + 'static>, Meter)>,
64
63
  trace_subscriber: Arc<dyn Subscriber + Send + Sync>,
64
+ prom_binding: Option<SocketAddr>,
65
65
  _keepalive_rx: Receiver<()>,
66
66
  }
67
67
 
@@ -71,6 +71,7 @@ impl TelemetryInstance {
71
71
  logs_out: Option<Mutex<CoreLogsOut>>,
72
72
  metric_prefix: &'static str,
73
73
  mut meter_provider: Option<Box<dyn MeterProvider + Send + Sync + 'static>>,
74
+ prom_binding: Option<SocketAddr>,
74
75
  keepalive_rx: Receiver<()>,
75
76
  ) -> Self {
76
77
  let metrics = meter_provider.take().map(|mp| {
@@ -82,6 +83,7 @@ impl TelemetryInstance {
82
83
  logs_out,
83
84
  metrics,
84
85
  trace_subscriber,
86
+ prom_binding,
85
87
  _keepalive_rx: keepalive_rx,
86
88
  }
87
89
  }
@@ -91,6 +93,18 @@ impl TelemetryInstance {
91
93
  pub fn trace_subscriber(&self) -> Arc<dyn Subscriber + Send + Sync> {
92
94
  self.trace_subscriber.clone()
93
95
  }
96
+
97
+ /// Returns the address the Prometheus server is bound to if it is running
98
+ pub fn prom_port(&self) -> Option<SocketAddr> {
99
+ self.prom_binding
100
+ }
101
+
102
+ /// Returns our wrapper for OTel metric meters, can be used to, ex: initialize clients
103
+ pub fn get_metric_meter(&self) -> Option<TemporalMeter> {
104
+ self.metrics
105
+ .as_ref()
106
+ .map(|(_, m)| TemporalMeter::new(m, self.metric_prefix))
107
+ }
94
108
  }
95
109
 
96
110
  thread_local! {
@@ -131,10 +145,6 @@ impl CoreTelemetry for TelemetryInstance {
131
145
  vec![]
132
146
  }
133
147
  }
134
-
135
- fn get_metric_meter(&self) -> Option<&Meter> {
136
- self.metrics.as_ref().map(|(_, m)| m)
137
- }
138
148
  }
139
149
 
140
150
  /// Initialize tracing subscribers/output and logging export, returning a [TelemetryInstance]
@@ -161,6 +171,7 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
161
171
  // Parts of telem dat ====
162
172
  let mut logs_out = None;
163
173
  let metric_prefix = metric_prefix(&opts);
174
+ let mut prom_binding = None;
164
175
  // =======================
165
176
 
166
177
  // Tracing subscriber layers =========
@@ -210,11 +221,14 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
210
221
  let aggregator = SDKAggSelector { metric_prefix };
211
222
  match metrics {
212
223
  MetricsExporter::Prometheus(addr) => {
213
- let srv = PromServer::new(
214
- *addr,
215
- aggregator,
216
- metric_temporality_to_selector(opts.metric_temporality),
217
- )?;
224
+ let srv = runtime.block_on(async move {
225
+ PromServer::new(
226
+ *addr,
227
+ aggregator,
228
+ metric_temporality_to_selector(opts.metric_temporality),
229
+ )
230
+ })?;
231
+ prom_binding = Some(srv.bound_addr());
218
232
  let mp = srv.exporter.meter_provider()?;
219
233
  runtime.spawn(async move { srv.run().await });
220
234
  Some(Box::new(mp) as Box<dyn MeterProvider + Send + Sync>)
@@ -286,6 +300,7 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
286
300
  logs_out,
287
301
  metric_prefix,
288
302
  meter_provider,
303
+ prom_binding,
289
304
  keepalive_rx,
290
305
  ))
291
306
  .expect("Must be able to send telem instance out of thread");
@@ -377,6 +392,7 @@ pub mod test_initters {
377
392
  .unwrap();
378
393
  }
379
394
  }
395
+ use crate::telemetry::metrics::TemporalMeter;
380
396
  #[cfg(test)]
381
397
  pub use test_initters::*;
382
398