@temporalio/core-bridge 1.5.2 → 1.7.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 (194) hide show
  1. package/Cargo.lock +304 -112
  2. package/lib/index.d.ts +8 -6
  3. package/lib/index.js.map +1 -1
  4. package/package.json +9 -4
  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/.buildkite/docker/Dockerfile +2 -2
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.buildkite/pipeline.yml +2 -4
  13. package/sdk-core/.cargo/config.toml +5 -2
  14. package/sdk-core/.github/workflows/heavy.yml +29 -0
  15. package/sdk-core/Cargo.toml +1 -1
  16. package/sdk-core/README.md +20 -10
  17. package/sdk-core/client/src/lib.rs +215 -39
  18. package/sdk-core/client/src/metrics.rs +17 -8
  19. package/sdk-core/client/src/raw.rs +4 -4
  20. package/sdk-core/client/src/retry.rs +32 -20
  21. package/sdk-core/core/Cargo.toml +25 -12
  22. package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
  23. package/sdk-core/core/src/abstractions.rs +204 -14
  24. package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
  25. package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
  26. package/sdk-core/core/src/core_tests/determinism.rs +165 -2
  27. package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
  28. package/sdk-core/core/src/core_tests/queries.rs +34 -16
  29. package/sdk-core/core/src/core_tests/workers.rs +8 -5
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
  32. package/sdk-core/core/src/internal_flags.rs +155 -0
  33. package/sdk-core/core/src/lib.rs +16 -9
  34. package/sdk-core/core/src/protosext/mod.rs +1 -1
  35. package/sdk-core/core/src/replay/mod.rs +16 -27
  36. package/sdk-core/core/src/telemetry/log_export.rs +1 -1
  37. package/sdk-core/core/src/telemetry/metrics.rs +69 -35
  38. package/sdk-core/core/src/telemetry/mod.rs +60 -21
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
  40. package/sdk-core/core/src/test_help/mod.rs +73 -14
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
  42. package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
  44. package/sdk-core/core/src/worker/activities.rs +350 -175
  45. package/sdk-core/core/src/worker/client/mocks.rs +22 -2
  46. package/sdk-core/core/src/worker/client.rs +18 -2
  47. package/sdk-core/core/src/worker/mod.rs +183 -64
  48. package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
  49. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
  50. package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
  51. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
  53. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
  54. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
  55. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
  56. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
  57. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
  58. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
  59. package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
  60. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
  61. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
  62. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
  63. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
  64. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
  65. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
  66. package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
  67. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
  68. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
  69. package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
  70. package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
  71. package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
  72. package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
  73. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
  74. package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
  75. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
  76. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
  77. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
  78. package/sdk-core/core-api/Cargo.toml +2 -1
  79. package/sdk-core/core-api/src/errors.rs +1 -34
  80. package/sdk-core/core-api/src/lib.rs +19 -9
  81. package/sdk-core/core-api/src/telemetry.rs +4 -6
  82. package/sdk-core/core-api/src/worker.rs +19 -1
  83. package/sdk-core/etc/deps.svg +115 -140
  84. package/sdk-core/etc/regen-depgraph.sh +5 -0
  85. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
  86. package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
  87. package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
  88. package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
  89. package/sdk-core/histories/old_change_marker_format.bin +0 -0
  90. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
  91. package/sdk-core/protos/api_upstream/Makefile +6 -6
  92. package/sdk-core/protos/api_upstream/build/go.mod +7 -0
  93. package/sdk-core/protos/api_upstream/build/go.sum +5 -0
  94. package/sdk-core/protos/api_upstream/build/tools.go +29 -0
  95. package/sdk-core/protos/api_upstream/go.mod +6 -0
  96. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
  97. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
  98. package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
  99. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
  100. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
  101. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
  102. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
  103. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
  104. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
  105. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
  106. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
  107. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
  108. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
  109. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
  110. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
  111. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
  112. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  113. package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
  114. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
  115. package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
  116. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
  117. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
  118. package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
  119. package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
  120. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
  121. package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  122. package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
  123. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
  124. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
  125. package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
  126. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
  127. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
  128. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
  129. package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
  130. package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
  131. package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
  132. package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
  133. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
  134. package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
  135. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
  136. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
  137. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
  138. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
  139. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
  140. package/sdk-core/sdk/Cargo.toml +5 -4
  141. package/sdk-core/sdk/src/lib.rs +108 -26
  142. package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
  143. package/sdk-core/sdk/src/workflow_context.rs +24 -17
  144. package/sdk-core/sdk/src/workflow_future.rs +16 -15
  145. package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
  146. package/sdk-core/sdk-core-protos/build.rs +36 -2
  147. package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
  148. package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
  149. package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
  150. package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
  151. package/sdk-core/test-utils/Cargo.toml +3 -1
  152. package/sdk-core/test-utils/src/canned_histories.rs +106 -296
  153. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  154. package/sdk-core/test-utils/src/lib.rs +82 -23
  155. package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
  156. package/sdk-core/test-utils/src/workflows.rs +29 -0
  157. package/sdk-core/tests/fuzzy_workflow.rs +130 -0
  158. package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
  159. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
  160. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
  161. package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
  162. package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
  163. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
  164. package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
  165. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
  166. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
  167. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
  168. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
  169. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
  170. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
  171. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
  172. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
  173. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
  174. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
  175. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
  176. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
  177. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
  178. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
  179. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
  180. package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
  181. package/sdk-core/tests/main.rs +3 -13
  182. package/sdk-core/tests/runner.rs +75 -36
  183. package/sdk-core/tests/wf_input_replay.rs +32 -0
  184. package/src/conversions.rs +14 -8
  185. package/src/runtime.rs +9 -8
  186. package/ts/index.ts +8 -6
  187. package/sdk-core/bridge-ffi/Cargo.toml +0 -24
  188. package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
  189. package/sdk-core/bridge-ffi/build.rs +0 -25
  190. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
  191. package/sdk-core/bridge-ffi/src/lib.rs +0 -746
  192. package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
  193. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
  194. package/sdk-core/sdk/src/conversions.rs +0 -8
@@ -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
  }
@@ -25,7 +25,18 @@ use opentelemetry::{
25
25
  };
26
26
  use opentelemetry_otlp::WithExportConfig;
27
27
  use parking_lot::Mutex;
28
- use std::{cell::RefCell, collections::VecDeque, convert::TryInto, env, sync::Arc, time::Duration};
28
+ use std::{
29
+ cell::RefCell,
30
+ collections::{HashMap, VecDeque},
31
+ convert::TryInto,
32
+ env,
33
+ net::SocketAddr,
34
+ sync::{
35
+ atomic::{AtomicBool, Ordering},
36
+ Arc,
37
+ },
38
+ time::Duration,
39
+ };
29
40
  use temporal_sdk_core_api::telemetry::{
30
41
  CoreLog, CoreTelemetry, Logger, MetricTemporality, MetricsExporter, OtelCollectorOptions,
31
42
  TelemetryOptions, TraceExporter,
@@ -37,12 +48,10 @@ use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Layer};
37
48
  const TELEM_SERVICE_NAME: &str = "temporal-core-sdk";
38
49
 
39
50
  /// Help you construct an [EnvFilter] compatible filter string which will forward all core module
40
- /// 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`.
41
52
  pub fn construct_filter_string(core_level: Level, other_level: Level) -> String {
42
53
  format!(
43
- "{o},temporal_sdk_core={l},temporal_client={l},temporal_sdk={l}",
44
- o = other_level,
45
- l = core_level
54
+ "{other_level},temporal_sdk_core={core_level},temporal_client={core_level},temporal_sdk={core_level}"
46
55
  )
47
56
  }
48
57
 
@@ -52,6 +61,7 @@ pub struct TelemetryInstance {
52
61
  logs_out: Option<Mutex<CoreLogsOut>>,
53
62
  metrics: Option<(Box<dyn MeterProvider + Send + Sync + 'static>, Meter)>,
54
63
  trace_subscriber: Arc<dyn Subscriber + Send + Sync>,
64
+ prom_binding: Option<SocketAddr>,
55
65
  _keepalive_rx: Receiver<()>,
56
66
  }
57
67
 
@@ -61,6 +71,7 @@ impl TelemetryInstance {
61
71
  logs_out: Option<Mutex<CoreLogsOut>>,
62
72
  metric_prefix: &'static str,
63
73
  mut meter_provider: Option<Box<dyn MeterProvider + Send + Sync + 'static>>,
74
+ prom_binding: Option<SocketAddr>,
64
75
  keepalive_rx: Receiver<()>,
65
76
  ) -> Self {
66
77
  let metrics = meter_provider.take().map(|mp| {
@@ -72,6 +83,7 @@ impl TelemetryInstance {
72
83
  logs_out,
73
84
  metrics,
74
85
  trace_subscriber,
86
+ prom_binding,
75
87
  _keepalive_rx: keepalive_rx,
76
88
  }
77
89
  }
@@ -81,6 +93,18 @@ impl TelemetryInstance {
81
93
  pub fn trace_subscriber(&self) -> Arc<dyn Subscriber + Send + Sync> {
82
94
  self.trace_subscriber.clone()
83
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
+ }
84
108
  }
85
109
 
86
110
  thread_local! {
@@ -121,10 +145,6 @@ impl CoreTelemetry for TelemetryInstance {
121
145
  vec![]
122
146
  }
123
147
  }
124
-
125
- fn get_metric_meter(&self) -> Option<&Meter> {
126
- self.metrics.as_ref().map(|(_, m)| m)
127
- }
128
148
  }
129
149
 
130
150
  /// Initialize tracing subscribers/output and logging export, returning a [TelemetryInstance]
@@ -151,6 +171,7 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
151
171
  // Parts of telem dat ====
152
172
  let mut logs_out = None;
153
173
  let metric_prefix = metric_prefix(&opts);
174
+ let mut prom_binding = None;
154
175
  // =======================
155
176
 
156
177
  // Tracing subscriber layers =========
@@ -200,11 +221,15 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
200
221
  let aggregator = SDKAggSelector { metric_prefix };
201
222
  match metrics {
202
223
  MetricsExporter::Prometheus(addr) => {
203
- let srv = PromServer::new(
204
- *addr,
205
- aggregator,
206
- metric_temporality_to_selector(opts.metric_temporality),
207
- )?;
224
+ let srv = runtime.block_on(async {
225
+ PromServer::new(
226
+ *addr,
227
+ aggregator,
228
+ metric_temporality_to_selector(opts.metric_temporality),
229
+ &opts.global_tags,
230
+ )
231
+ })?;
232
+ prom_binding = Some(srv.bound_addr());
208
233
  let mp = srv.exporter.meter_provider()?;
209
234
  runtime.spawn(async move { srv.run().await });
210
235
  Some(Box::new(mp) as Box<dyn MeterProvider + Send + Sync>)
@@ -221,7 +246,7 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
221
246
  runtime::Tokio,
222
247
  )
223
248
  .with_period(metric_periodicity.unwrap_or_else(|| Duration::from_secs(1)))
224
- .with_resource(default_resource())
249
+ .with_resource(default_resource(&opts.global_tags))
225
250
  .with_exporter(
226
251
  opentelemetry_otlp::new_exporter()
227
252
  .tonic()
@@ -242,7 +267,8 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
242
267
  match &tracing.exporter {
243
268
  TraceExporter::Otel(OtelCollectorOptions { url, headers, .. }) => {
244
269
  runtime.block_on(async {
245
- let tracer_cfg = Config::default().with_resource(default_resource());
270
+ let tracer_cfg =
271
+ Config::default().with_resource(default_resource(&opts.global_tags));
246
272
  let tracer = opentelemetry_otlp::new_pipeline()
247
273
  .tracing()
248
274
  .with_exporter(
@@ -276,6 +302,7 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
276
302
  logs_out,
277
303
  metric_prefix,
278
304
  meter_provider,
305
+ prom_binding,
279
306
  keepalive_rx,
280
307
  ))
281
308
  .expect("Must be able to send telem instance out of thread");
@@ -295,10 +322,17 @@ pub fn telemetry_init(opts: TelemetryOptions) -> Result<TelemetryInstance, anyho
295
322
  }
296
323
  }
297
324
 
298
- /// Initialize telemetry/tracing globally. Useful for testing.
325
+ /// Initialize telemetry/tracing globally. Useful for testing. Only takes affect when called
326
+ /// the first time. Subsequent calls are ignored.
299
327
  pub fn telemetry_init_global(opts: TelemetryOptions) -> Result<(), anyhow::Error> {
300
- let ti = telemetry_init(opts)?;
301
- tracing::subscriber::set_global_default(ti.trace_subscriber())?;
328
+ static INITTED: AtomicBool = AtomicBool::new(false);
329
+ if INITTED
330
+ .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
331
+ .is_ok()
332
+ {
333
+ let ti = telemetry_init(opts)?;
334
+ tracing::subscriber::set_global_default(ti.trace_subscriber())?;
335
+ }
302
336
  Ok(())
303
337
  }
304
338
 
@@ -306,8 +340,12 @@ fn default_resource_kvs() -> &'static [KeyValue] {
306
340
  static INSTANCE: OnceCell<[KeyValue; 1]> = OnceCell::new();
307
341
  INSTANCE.get_or_init(|| [KeyValue::new("service.name", TELEM_SERVICE_NAME)])
308
342
  }
309
- fn default_resource() -> Resource {
310
- Resource::new(default_resource_kvs().iter().cloned())
343
+
344
+ fn default_resource(override_values: &HashMap<String, String>) -> Resource {
345
+ let override_kvs = override_values
346
+ .iter()
347
+ .map(|(k, v)| KeyValue::new(k.clone(), v.clone()));
348
+ Resource::new(default_resource_kvs().iter().cloned()).merge(&Resource::new(override_kvs))
311
349
  }
312
350
 
313
351
  fn metric_temporality_to_selector(
@@ -360,6 +398,7 @@ pub mod test_initters {
360
398
  .unwrap();
361
399
  }
362
400
  }
401
+ use crate::telemetry::metrics::TemporalMeter;
363
402
  #[cfg(test)]
364
403
  pub use test_initters::*;
365
404
 
@@ -1,23 +1,21 @@
1
1
  use crate::telemetry::default_resource;
2
2
  use hyper::{
3
3
  header::CONTENT_TYPE,
4
+ server::conn::AddrIncoming,
4
5
  service::{make_service_fn, service_fn},
5
6
  Body, Method, Request, Response, Server,
6
7
  };
7
- use opentelemetry::{
8
- metrics::MetricsError,
9
- sdk::{
10
- export::metrics::{aggregation::TemporalitySelector, AggregatorSelector},
11
- metrics::{controllers, processors},
12
- },
8
+ use opentelemetry::sdk::{
9
+ export::metrics::{aggregation::TemporalitySelector, AggregatorSelector},
10
+ metrics::{controllers, processors},
13
11
  };
14
12
  use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
15
13
  use prometheus::{Encoder, TextEncoder};
16
- use std::{convert::Infallible, net::SocketAddr, sync::Arc};
14
+ use std::{collections::HashMap, convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
17
15
 
18
16
  /// Exposes prometheus metrics for scraping
19
17
  pub(super) struct PromServer {
20
- addr: SocketAddr,
18
+ bound_addr: AddrIncoming,
21
19
  pub exporter: Arc<PrometheusExporter>,
22
20
  }
23
21
 
@@ -26,19 +24,23 @@ impl PromServer {
26
24
  addr: SocketAddr,
27
25
  aggregation: impl AggregatorSelector + Send + Sync + 'static,
28
26
  temporality: impl TemporalitySelector + Send + Sync + 'static,
29
- ) -> Result<Self, MetricsError> {
27
+ tags: &HashMap<String, String>,
28
+ ) -> Result<Self, anyhow::Error> {
30
29
  let controller =
31
30
  controllers::basic(processors::factory(aggregation, temporality).with_memory(true))
32
- .with_resource(default_resource())
31
+ // Because Prom is pull-based, make this always refresh
32
+ .with_collect_period(Duration::from_secs(0))
33
+ .with_resource(default_resource(tags))
33
34
  .build();
34
35
  let exporter = ExporterBuilder::new(controller).try_init()?;
36
+ let bound_addr = AddrIncoming::bind(&addr)?;
35
37
  Ok(Self {
36
38
  exporter: Arc::new(exporter),
37
- addr,
39
+ bound_addr,
38
40
  })
39
41
  }
40
42
 
41
- pub async fn run(&self) -> hyper::Result<()> {
43
+ pub async fn run(self) -> hyper::Result<()> {
42
44
  // Spin up hyper server to serve metrics for scraping. We use hyper since we already depend
43
45
  // on it via Tonic.
44
46
  let expclone = self.exporter.clone();
@@ -46,9 +48,13 @@ impl PromServer {
46
48
  let expclone = expclone.clone();
47
49
  async move { Ok::<_, Infallible>(service_fn(move |req| metrics_req(req, expclone.clone()))) }
48
50
  });
49
- let server = Server::bind(&self.addr).serve(svc);
51
+ let server = Server::builder(self.bound_addr).serve(svc);
50
52
  server.await
51
53
  }
54
+
55
+ pub fn bound_addr(&self) -> SocketAddr {
56
+ self.bound_addr.local_addr()
57
+ }
52
58
  }
53
59
 
54
60
  /// Serves prometheus metrics in the expected format for scraping
@@ -14,6 +14,7 @@ use crate::{
14
14
  },
15
15
  TaskToken, Worker, WorkerConfig, WorkerConfigBuilder,
16
16
  };
17
+ use async_trait::async_trait;
17
18
  use bimap::BiMap;
18
19
  use futures::{future::BoxFuture, stream, stream::BoxStream, FutureExt, Stream, StreamExt};
19
20
  use mockall::TimesRange;
@@ -29,7 +30,10 @@ use std::{
29
30
  task::{Context, Poll},
30
31
  time::Duration,
31
32
  };
32
- use temporal_sdk_core_api::Worker as WorkerTrait;
33
+ use temporal_sdk_core_api::{
34
+ errors::{PollActivityError, PollWfError},
35
+ Worker as WorkerTrait,
36
+ };
33
37
  use temporal_sdk_core_protos::{
34
38
  coresdk::{
35
39
  workflow_activation::WorkflowActivation,
@@ -52,7 +56,6 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
52
56
  use tokio_util::sync::CancellationToken;
53
57
 
54
58
  pub const TEST_Q: &str = "q";
55
- pub static NO_MORE_WORK_ERROR_MSG: &str = "No more work to do";
56
59
 
57
60
  pub fn test_worker_cfg() -> WorkerConfigBuilder {
58
61
  let mut wcb = WorkerConfigBuilder::default();
@@ -148,6 +151,7 @@ pub(crate) fn mock_worker(mocks: MocksHolder) -> Worker {
148
151
  mocks.inputs.wft_stream,
149
152
  act_poller,
150
153
  MetricsContext::no_op(),
154
+ None,
151
155
  CancellationToken::new(),
152
156
  )
153
157
  }
@@ -301,7 +305,7 @@ where
301
305
  }
302
306
  .boxed()
303
307
  } else {
304
- async { Some(Err(tonic::Status::cancelled(NO_MORE_WORK_ERROR_MSG))) }.boxed()
308
+ async { None }.boxed()
305
309
  }
306
310
  });
307
311
  Box::new(mock_poller) as BoxedPoller<T>
@@ -375,10 +379,12 @@ pub(crate) struct MockPollCfg {
375
379
  pub expect_fail_wft_matcher:
376
380
  Box<dyn Fn(&TaskToken, &WorkflowTaskFailedCause, &Option<Failure>) -> bool + Send>,
377
381
  pub completion_asserts: Option<Box<dyn Fn(&WorkflowTaskCompletion) + Send>>,
382
+ pub num_expected_completions: Option<TimesRange>,
378
383
  /// If being used with the Rust SDK, this is set true. It ensures pollers will not error out
379
384
  /// early with no work, since we cannot know the exact number of times polling will happen.
380
385
  /// Instead, they will just block forever.
381
386
  pub using_rust_sdk: bool,
387
+ pub make_poll_stream_interminable: bool,
382
388
  }
383
389
 
384
390
  impl MockPollCfg {
@@ -395,7 +401,9 @@ impl MockPollCfg {
395
401
  mock_client: mock_workflow_client(),
396
402
  expect_fail_wft_matcher: Box::new(|_, _, _| true),
397
403
  completion_asserts: None,
404
+ num_expected_completions: None,
398
405
  using_rust_sdk: false,
406
+ make_poll_stream_interminable: false,
399
407
  }
400
408
  }
401
409
  pub fn from_resp_batches(
@@ -416,7 +424,9 @@ impl MockPollCfg {
416
424
  mock_client,
417
425
  expect_fail_wft_matcher: Box::new(|_, _, _| true),
418
426
  completion_asserts: None,
427
+ num_expected_completions: None,
419
428
  using_rust_sdk: false,
429
+ make_poll_stream_interminable: false,
420
430
  }
421
431
  }
422
432
  }
@@ -584,16 +594,20 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
584
594
  );
585
595
 
586
596
  let outstanding = outstanding_wf_task_tokens.clone();
587
- cfg.mock_client
588
- .expect_complete_workflow_task()
589
- .returning(move |comp| {
590
- if let Some(ass) = cfg.completion_asserts.as_ref() {
591
- // tee hee
592
- ass(&comp)
593
- }
594
- outstanding.release_token(&comp.task_token);
595
- Ok(RespondWorkflowTaskCompletedResponse::default())
596
- });
597
+ let expect_completes = cfg.mock_client.expect_complete_workflow_task();
598
+ if let Some(range) = cfg.num_expected_completions {
599
+ expect_completes.times(range);
600
+ } else if cfg.completion_asserts.is_some() {
601
+ expect_completes.times(1..);
602
+ }
603
+ expect_completes.returning(move |comp| {
604
+ if let Some(ass) = cfg.completion_asserts.as_ref() {
605
+ // tee hee
606
+ ass(&comp)
607
+ }
608
+ outstanding.release_token(&comp.task_token);
609
+ Ok(RespondWorkflowTaskCompletedResponse::default())
610
+ });
597
611
  let outstanding = outstanding_wf_task_tokens.clone();
598
612
  cfg.mock_client
599
613
  .expect_fail_workflow_task()
@@ -612,11 +626,15 @@ pub(crate) fn build_mock_pollers(mut cfg: MockPollCfg) -> MocksHolder {
612
626
  Ok(Default::default())
613
627
  });
614
628
 
615
- MocksHolder {
629
+ let mut mh = MocksHolder {
616
630
  client: Arc::new(cfg.mock_client),
617
631
  inputs: mock_worker,
618
632
  outstanding_task_map: Some(outstanding_wf_task_tokens),
633
+ };
634
+ if cfg.make_poll_stream_interminable {
635
+ mh.make_wft_stream_interminable();
619
636
  }
637
+ mh
620
638
  }
621
639
 
622
640
  pub struct QueueResponse<T> {
@@ -835,6 +853,7 @@ pub(crate) fn gen_assert_and_fail(asserter: &dyn Fn(&WorkflowActivation)) -> Ass
835
853
  message: "Intentional test failure".to_string(),
836
854
  ..Default::default()
837
855
  }),
856
+ ..Default::default()
838
857
  }
839
858
  .into(),
840
859
  )
@@ -880,3 +899,43 @@ macro_rules! prost_dur {
880
899
  .expect("test duration fits")
881
900
  };
882
901
  }
902
+
903
+ #[async_trait]
904
+ pub(crate) trait WorkerExt {
905
+ /// Initiate shutdown, drain the pollers, and wait for shutdown to complete.
906
+ async fn drain_pollers_and_shutdown(self);
907
+ /// Initiate shutdown, drain the *activity* poller, and wait for shutdown to complete.
908
+ /// Takes a ref because of that one test that needs it.
909
+ async fn drain_activity_poller_and_shutdown(&self);
910
+ }
911
+
912
+ #[async_trait]
913
+ impl WorkerExt for Worker {
914
+ async fn drain_pollers_and_shutdown(self) {
915
+ self.initiate_shutdown();
916
+ tokio::join!(
917
+ async {
918
+ assert_matches!(
919
+ self.poll_activity_task().await.unwrap_err(),
920
+ PollActivityError::ShutDown
921
+ );
922
+ },
923
+ async {
924
+ assert_matches!(
925
+ self.poll_workflow_activation().await.unwrap_err(),
926
+ PollWfError::ShutDown
927
+ );
928
+ }
929
+ );
930
+ self.finalize_shutdown().await;
931
+ }
932
+
933
+ async fn drain_activity_poller_and_shutdown(&self) {
934
+ self.initiate_shutdown();
935
+ assert_matches!(
936
+ self.poll_activity_task().await.unwrap_err(),
937
+ PollActivityError::ShutDown
938
+ );
939
+ self.shutdown().await;
940
+ }
941
+ }