@temporalio/core-bridge 1.9.2 → 1.10.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 (177) hide show
  1. package/Cargo.lock +754 -473
  2. package/Cargo.toml +3 -3
  3. package/lib/index.d.ts +33 -2
  4. package/lib/index.js.map +1 -1
  5. package/package.json +4 -4
  6. package/releases/aarch64-apple-darwin/index.node +0 -0
  7. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  8. package/releases/x86_64-apple-darwin/index.node +0 -0
  9. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  10. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  11. package/scripts/build.js +4 -3
  12. package/sdk-core/.cargo/config.toml +2 -4
  13. package/sdk-core/.github/workflows/heavy.yml +1 -1
  14. package/sdk-core/.github/workflows/per-pr.yml +6 -4
  15. package/sdk-core/Cargo.toml +10 -3
  16. package/sdk-core/README.md +4 -6
  17. package/sdk-core/client/Cargo.toml +13 -5
  18. package/sdk-core/client/src/lib.rs +123 -34
  19. package/sdk-core/client/src/metrics.rs +70 -18
  20. package/sdk-core/client/src/proxy.rs +85 -0
  21. package/sdk-core/client/src/raw.rs +67 -5
  22. package/sdk-core/client/src/worker_registry/mod.rs +5 -3
  23. package/sdk-core/client/src/workflow_handle/mod.rs +3 -1
  24. package/sdk-core/core/Cargo.toml +31 -37
  25. package/sdk-core/core/src/abstractions/take_cell.rs +3 -3
  26. package/sdk-core/core/src/abstractions.rs +176 -108
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -13
  28. package/sdk-core/core/src/core_tests/determinism.rs +2 -1
  29. package/sdk-core/core/src/core_tests/local_activities.rs +3 -3
  30. package/sdk-core/core/src/core_tests/mod.rs +3 -3
  31. package/sdk-core/core/src/core_tests/queries.rs +42 -5
  32. package/sdk-core/core/src/core_tests/workers.rs +2 -3
  33. package/sdk-core/core/src/core_tests/workflow_tasks.rs +115 -15
  34. package/sdk-core/core/src/ephemeral_server/mod.rs +109 -136
  35. package/sdk-core/core/src/internal_flags.rs +8 -8
  36. package/sdk-core/core/src/lib.rs +16 -11
  37. package/sdk-core/core/src/pollers/mod.rs +11 -5
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +48 -29
  39. package/sdk-core/core/src/protosext/mod.rs +32 -32
  40. package/sdk-core/core/src/protosext/protocol_messages.rs +14 -24
  41. package/sdk-core/core/src/retry_logic.rs +2 -2
  42. package/sdk-core/core/src/telemetry/log_export.rs +10 -9
  43. package/sdk-core/core/src/telemetry/metrics.rs +233 -330
  44. package/sdk-core/core/src/telemetry/mod.rs +11 -38
  45. package/sdk-core/core/src/telemetry/otel.rs +355 -0
  46. package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -23
  47. package/sdk-core/core/src/test_help/mod.rs +80 -59
  48. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +6 -6
  49. package/sdk-core/core/src/worker/activities/local_activities.rs +46 -43
  50. package/sdk-core/core/src/worker/activities.rs +45 -46
  51. package/sdk-core/core/src/worker/client/mocks.rs +8 -7
  52. package/sdk-core/core/src/worker/client.rs +40 -39
  53. package/sdk-core/core/src/worker/mod.rs +72 -42
  54. package/sdk-core/core/src/worker/slot_provider.rs +28 -28
  55. package/sdk-core/core/src/worker/slot_supplier.rs +1 -0
  56. package/sdk-core/core/src/worker/tuner/fixed_size.rs +52 -0
  57. package/sdk-core/core/src/worker/tuner/resource_based.rs +561 -0
  58. package/sdk-core/core/src/worker/tuner.rs +122 -0
  59. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +6 -6
  60. package/sdk-core/core/src/worker/workflow/history_update.rs +27 -53
  61. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +4 -17
  62. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -10
  63. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +4 -11
  64. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +17 -35
  65. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +0 -8
  66. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -5
  67. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +0 -5
  68. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +0 -5
  69. package/sdk-core/core/src/worker/workflow/machines/mod.rs +0 -14
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -5
  71. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +0 -5
  72. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -10
  73. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -10
  74. package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +12 -8
  75. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +0 -10
  76. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -13
  77. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +27 -37
  78. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +3 -14
  79. package/sdk-core/core/src/worker/workflow/managed_run.rs +84 -54
  80. package/sdk-core/core/src/worker/workflow/mod.rs +63 -160
  81. package/sdk-core/core/src/worker/workflow/run_cache.rs +22 -13
  82. package/sdk-core/core/src/worker/workflow/wft_extraction.rs +16 -3
  83. package/sdk-core/core/src/worker/workflow/wft_poller.rs +15 -12
  84. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +39 -78
  85. package/sdk-core/core-api/Cargo.toml +6 -5
  86. package/sdk-core/core-api/src/errors.rs +8 -0
  87. package/sdk-core/core-api/src/telemetry/metrics.rs +75 -4
  88. package/sdk-core/core-api/src/telemetry.rs +7 -1
  89. package/sdk-core/core-api/src/worker.rs +212 -56
  90. package/sdk-core/fsm/Cargo.toml +3 -0
  91. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
  92. package/sdk-core/sdk/Cargo.toml +5 -7
  93. package/sdk-core/sdk/src/app_data.rs +3 -3
  94. package/sdk-core/sdk/src/lib.rs +5 -3
  95. package/sdk-core/sdk/src/workflow_context/options.rs +1 -1
  96. package/sdk-core/sdk/src/workflow_context.rs +10 -9
  97. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  98. package/sdk-core/sdk-core-protos/Cargo.toml +8 -6
  99. package/sdk-core/sdk-core-protos/build.rs +1 -10
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +3 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/ci.yml +26 -0
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +42 -20
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +2 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +36 -26
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +2 -0
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/struct.proto +95 -0
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +9632 -0
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +7337 -0
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/payload_description.txt +2 -0
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +45 -11
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +22 -4
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +2 -0
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +44 -0
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +18 -3
  115. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -0
  116. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +30 -0
  117. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +7 -8
  118. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +23 -5
  119. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +20 -0
  120. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +25 -0
  121. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +141 -15
  122. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +12 -0
  123. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +193 -0
  124. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +73 -6
  125. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +46 -4
  126. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +4 -0
  127. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +2 -2
  128. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +116 -0
  129. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +134 -0
  130. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +274 -29
  131. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +57 -1
  132. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +10 -12
  133. package/sdk-core/sdk-core-protos/src/history_builder.rs +1 -1
  134. package/sdk-core/sdk-core-protos/src/lib.rs +54 -51
  135. package/sdk-core/sdk-core-protos/src/task_token.rs +11 -2
  136. package/sdk-core/test-utils/Cargo.toml +7 -4
  137. package/sdk-core/test-utils/src/histfetch.rs +1 -1
  138. package/sdk-core/test-utils/src/lib.rs +44 -62
  139. package/sdk-core/tests/fuzzy_workflow.rs +5 -2
  140. package/sdk-core/tests/heavy_tests.rs +114 -17
  141. package/sdk-core/tests/integ_tests/activity_functions.rs +1 -1
  142. package/sdk-core/tests/integ_tests/client_tests.rs +2 -2
  143. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +38 -26
  144. package/sdk-core/tests/integ_tests/metrics_tests.rs +126 -17
  145. package/sdk-core/tests/integ_tests/polling_tests.rs +118 -2
  146. package/sdk-core/tests/integ_tests/update_tests.rs +3 -5
  147. package/sdk-core/tests/integ_tests/visibility_tests.rs +3 -3
  148. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +1 -1
  149. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  150. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
  151. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  152. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +3 -3
  153. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -4
  154. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -2
  155. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +6 -10
  156. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +9 -7
  157. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -1
  158. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +14 -9
  159. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
  160. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +6 -13
  161. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +9 -6
  162. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +5 -5
  163. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
  164. package/sdk-core/tests/integ_tests/workflow_tests.rs +115 -11
  165. package/sdk-core/tests/main.rs +2 -2
  166. package/src/conversions.rs +57 -0
  167. package/src/lib.rs +1 -0
  168. package/src/runtime.rs +51 -35
  169. package/ts/index.ts +67 -3
  170. package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +0 -117
  171. package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +0 -24
  172. package/sdk-core/sdk/src/payload_converter.rs +0 -11
  173. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +0 -2
  174. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/docker-compose.yml +0 -15
  175. package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/pipeline.yml +0 -10
  176. package/sdk-core/test-utils/src/wf_input_saver.rs +0 -50
  177. package/sdk-core/tests/wf_input_replay.rs +0 -32
@@ -1,9 +1,14 @@
1
1
  use futures::{future::join_all, sink, stream::FuturesUnordered, StreamExt};
2
- use std::time::{Duration, Instant};
2
+ use std::{
3
+ sync::Arc,
4
+ time::{Duration, Instant},
5
+ };
3
6
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
4
7
  use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
5
- use temporal_sdk_core_protos::coresdk::{
6
- workflow_commands::ActivityCancellationType, AsJsonPayloadExt,
8
+ use temporal_sdk_core::{ResourceBasedSlots, ResourceBasedTuner, ResourceSlotOptions};
9
+ use temporal_sdk_core_protos::{
10
+ coresdk::{workflow_commands::ActivityCancellationType, AsJsonPayloadExt},
11
+ temporal::api::enums::v1::WorkflowIdReusePolicy,
7
12
  };
8
13
  use temporal_sdk_core_test_utils::{workflows::la_problem_workflow, CoreWfStarter};
9
14
 
@@ -15,10 +20,11 @@ async fn activity_load() {
15
20
 
16
21
  let mut starter = CoreWfStarter::new("activity_load");
17
22
  starter
18
- .max_wft(CONCURRENCY)
23
+ .worker_config
24
+ .max_outstanding_workflow_tasks(CONCURRENCY)
19
25
  .max_cached_workflows(CONCURRENCY)
20
- .max_at_polls(10)
21
- .max_at(CONCURRENCY);
26
+ .max_concurrent_at_polls(10_usize)
27
+ .max_outstanding_activities(CONCURRENCY);
22
28
  let mut worker = starter.worker().await;
23
29
 
24
30
  let activity_id = "act-1";
@@ -78,24 +84,111 @@ async fn activity_load() {
78
84
  dbg!(running.elapsed());
79
85
  }
80
86
 
87
+ #[tokio::test]
88
+ async fn chunky_activities_resource_based() {
89
+ const WORKFLOWS: usize = 100;
90
+
91
+ let mut starter = CoreWfStarter::new("chunky_activities_resource_based");
92
+ starter
93
+ .worker_config
94
+ .clear_max_outstanding_opts()
95
+ .max_concurrent_wft_polls(10_usize)
96
+ .max_concurrent_at_polls(10_usize);
97
+ let mut tuner = ResourceBasedTuner::new(ResourceBasedSlots::new(0.7, 0.7));
98
+ tuner
99
+ .with_workflow_slots_options(ResourceSlotOptions::new(
100
+ 25,
101
+ WORKFLOWS,
102
+ Duration::from_millis(0),
103
+ ))
104
+ .with_activity_slots_options(ResourceSlotOptions::new(5, 1000, Duration::from_millis(50)));
105
+ starter.worker_config.tuner(Arc::new(tuner));
106
+ let mut worker = starter.worker().await;
107
+
108
+ let activity_id = "act-1";
109
+ let activity_timeout = Duration::from_secs(30);
110
+
111
+ let wf_fn = move |ctx: WfContext| {
112
+ let payload = "yo".as_json_payload().unwrap();
113
+ async move {
114
+ let activity = ActivityOptions {
115
+ activity_id: Some(activity_id.to_string()),
116
+ activity_type: "test_activity".to_string(),
117
+ input: payload.clone(),
118
+ start_to_close_timeout: Some(activity_timeout),
119
+ ..Default::default()
120
+ };
121
+ let res = ctx.activity(activity).await.unwrap_ok_payload();
122
+ assert_eq!(res.data, payload.data);
123
+ Ok(().into())
124
+ }
125
+ };
126
+
127
+ let starting = Instant::now();
128
+ let wf_type = "chunky_activity_wf";
129
+ worker.register_wf(wf_type.to_owned(), wf_fn);
130
+ worker.register_activity(
131
+ "test_activity",
132
+ |_ctx: ActContext, echo: String| async move {
133
+ tokio::task::spawn_blocking(move || {
134
+ // Allocate a gig and then do some CPU stuff on it
135
+ let mut mem = vec![0_u8; 1000 * 1024 * 1024];
136
+ for _ in 1..10 {
137
+ for i in 0..mem.len() {
138
+ mem[i] &= mem[mem.len() - 1 - i]
139
+ }
140
+ }
141
+ Ok(echo)
142
+ })
143
+ .await?
144
+ },
145
+ );
146
+ join_all((0..WORKFLOWS).map(|i| {
147
+ let worker = &worker;
148
+ let wf_id = format!("chunk_activity_{i}");
149
+ async move {
150
+ worker
151
+ .submit_wf(
152
+ wf_id,
153
+ wf_type.to_owned(),
154
+ vec![],
155
+ WorkflowOptions {
156
+ id_reuse_policy: WorkflowIdReusePolicy::TerminateIfRunning,
157
+ ..Default::default()
158
+ },
159
+ )
160
+ .await
161
+ .unwrap();
162
+ }
163
+ }))
164
+ .await;
165
+ dbg!(starting.elapsed());
166
+
167
+ let running = Instant::now();
168
+
169
+ worker.run_until_done().await.unwrap();
170
+ dbg!(running.elapsed());
171
+ }
172
+
81
173
  #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
82
174
  async fn workflow_load() {
83
175
  const SIGNAME: &str = "signame";
84
- let num_workflows = 200;
176
+ let num_workflows = 500;
85
177
  let wf_name = "workflow_load";
86
178
  let mut starter = CoreWfStarter::new("workflow_load");
87
179
  starter
88
- .max_wft(5)
89
- .max_cached_workflows(5)
90
- .max_at_polls(10)
91
- .max_at(100);
180
+ .worker_config
181
+ .max_outstanding_workflow_tasks(5_usize)
182
+ .max_cached_workflows(200_usize)
183
+ .max_concurrent_at_polls(10_usize)
184
+ .max_outstanding_activities(100_usize);
92
185
  let mut worker = starter.worker().await;
93
186
  worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
94
187
  let sigchan = ctx.make_signal_channel(SIGNAME).map(Ok);
95
188
  let drained_fut = sigchan.forward(sink::drain());
96
189
 
97
190
  let real_stuff = async move {
98
- for _ in 0..20 {
191
+ for _ in 0..5 {
99
192
  ctx.activity(ActivityOptions {
100
193
  activity_type: "echo_activity".to_string(),
101
194
  start_to_close_timeout: Some(Duration::from_secs(5)),
@@ -162,8 +255,10 @@ async fn workflow_load() {
162
255
  async fn evict_while_la_running_no_interference() {
163
256
  let wf_name = "evict_while_la_running_no_interference";
164
257
  let mut starter = CoreWfStarter::new(wf_name);
165
- starter.max_local_at(20);
166
- starter.max_cached_workflows(20);
258
+ starter
259
+ .worker_config
260
+ .max_outstanding_local_activities(20_usize)
261
+ .max_cached_workflows(20_usize);
167
262
  // Though it doesn't make sense to set wft higher than cached workflows, leaving this commented
168
263
  // introduces more instability that can be useful in the test.
169
264
  // starter.max_wft(20);
@@ -228,9 +323,11 @@ pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()>
228
323
  async fn can_paginate_long_history() {
229
324
  let wf_name = "can_paginate_long_history";
230
325
  let mut starter = CoreWfStarter::new(wf_name);
231
- starter.no_remote_activities();
232
- // Do not use sticky queues so we are forced to paginate once history gets long
233
- starter.max_cached_workflows(0);
326
+ starter
327
+ .worker_config
328
+ .no_remote_activities(true)
329
+ // Do not use sticky queues so we are forced to paginate once history gets long
330
+ .max_cached_workflows(0_usize);
234
331
 
235
332
  let mut worker = starter.worker().await;
236
333
  worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
@@ -1,5 +1,5 @@
1
1
  use temporal_sdk::ActContext;
2
2
 
3
- pub async fn echo(_ctx: ActContext, e: String) -> anyhow::Result<String> {
3
+ pub(crate) async fn echo(_ctx: ActContext, e: String) -> anyhow::Result<String> {
4
4
  Ok(e)
5
5
  }
@@ -17,7 +17,7 @@ async fn can_use_retry_client() {
17
17
  #[tokio::test]
18
18
  async fn can_use_retry_raw_client() {
19
19
  let opts = get_integ_server_options();
20
- let raw_client = opts.connect_no_namespace(None, None).await.unwrap();
20
+ let raw_client = opts.connect_no_namespace(None).await.unwrap();
21
21
  let mut retry_client = RetryClient::new(raw_client, opts.retry_config);
22
22
  retry_client
23
23
  .describe_namespace(DescribeNamespaceRequest {
@@ -31,6 +31,6 @@ async fn can_use_retry_raw_client() {
31
31
  #[tokio::test]
32
32
  async fn calls_get_system_info() {
33
33
  let opts = get_integ_server_options();
34
- let raw_client = opts.connect_no_namespace(None, None).await.unwrap();
34
+ let raw_client = opts.connect_no_namespace(None).await.unwrap();
35
35
  assert!(raw_client.get_client().capabilities().is_some());
36
36
  }
@@ -1,8 +1,10 @@
1
+ use futures::stream;
2
+ use futures::TryStreamExt;
1
3
  use std::time::{SystemTime, UNIX_EPOCH};
2
4
  use temporal_client::{ClientOptionsBuilder, TestService, WorkflowService};
3
5
  use temporal_sdk_core::ephemeral_server::{
4
6
  EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporalDevServerConfigBuilder,
5
- TemporaliteConfigBuilder, TestServerConfigBuilder,
7
+ TestServerConfigBuilder,
6
8
  };
7
9
  use temporal_sdk_core_protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
8
10
  use temporal_sdk_core_test_utils::{default_cached_download, NAMESPACE};
@@ -16,7 +18,12 @@ async fn temporal_cli_default() {
16
18
  .unwrap();
17
19
  let mut server = config.start_server().await.unwrap();
18
20
  assert_ephemeral_server(&server).await;
21
+
22
+ // Make sure process is there on start and not there after shutdown
23
+ let pid = sysinfo::Pid::from_u32(server.child_process_id().unwrap());
24
+ assert!(sysinfo::System::new_all().process(pid).is_some());
19
25
  server.shutdown().await.unwrap();
26
+ assert!(sysinfo::System::new_all().process(pid).is_none());
20
27
  }
21
28
 
22
29
  #[tokio::test]
@@ -31,32 +38,10 @@ async fn temporal_cli_fixed() {
31
38
  }
32
39
 
33
40
  #[tokio::test]
34
- async fn temporalite_default() {
35
- let config = TemporaliteConfigBuilder::default()
36
- .exe(default_cached_download())
37
- .build()
38
- .unwrap();
39
- let mut server = config.start_server().await.unwrap();
40
- assert_ephemeral_server(&server).await;
41
- server.shutdown().await.unwrap();
42
- }
43
-
44
- #[tokio::test]
45
- async fn temporalite_fixed() {
46
- let config = TemporaliteConfigBuilder::default()
47
- .exe(fixed_cached_download("v0.2.0"))
48
- .build()
49
- .unwrap();
50
- let mut server = config.start_server().await.unwrap();
51
- assert_ephemeral_server(&server).await;
52
- server.shutdown().await.unwrap();
53
- }
54
-
55
- #[tokio::test]
56
- async fn temporalite_shutdown_port_reuse() {
41
+ async fn temporal_cli_shutdown_port_reuse() {
57
42
  // Start, test shutdown, do again immediately on same port to ensure we can
58
43
  // reuse after shutdown
59
- let config = TemporaliteConfigBuilder::default()
44
+ let config = TemporalDevServerConfigBuilder::default()
60
45
  .exe(default_cached_download())
61
46
  .port(Some(10123))
62
47
  .build()
@@ -69,6 +54,33 @@ async fn temporalite_shutdown_port_reuse() {
69
54
  server.shutdown().await.unwrap();
70
55
  }
71
56
 
57
+ // This test will fail on Linux until https://github.com/temporalio/cli/pull/564
58
+ // gets released (presumably in 0.12.1). To test locally, build CLI manually
59
+ // and use that specific binary instead:
60
+ // ```
61
+ // .exe(EphemeralExe::ExistingPath(
62
+ // "/usr/local/bin/temporal".to_string(),
63
+ // ))
64
+ // ```
65
+ #[tokio::test]
66
+ #[ignore]
67
+ async fn temporal_cli_concurrent_starts() -> Result<(), Box<dyn std::error::Error>> {
68
+ stream::iter((0..80).map(|_| {
69
+ TemporalDevServerConfigBuilder::default()
70
+ .exe(default_cached_download())
71
+ .build()
72
+ .map_err(anyhow::Error::from)
73
+ }))
74
+ .try_for_each_concurrent(8, |config| async move {
75
+ let mut server = config.start_server().await?;
76
+ server.shutdown().await?;
77
+ Ok(())
78
+ })
79
+ .await?;
80
+
81
+ Ok(())
82
+ }
83
+
72
84
  #[tokio::test]
73
85
  async fn test_server_default() {
74
86
  let config = TestServerConfigBuilder::default()
@@ -124,7 +136,7 @@ async fn assert_ephemeral_server(server: &EphemeralServer) {
124
136
  .client_version("0.1.0".to_string())
125
137
  .build()
126
138
  .unwrap()
127
- .connect_no_namespace(None, None)
139
+ .connect_no_namespace(None)
128
140
  .await
129
141
  .unwrap();
130
142
  let resp = client
@@ -23,8 +23,10 @@ use temporal_sdk_core_protos::{
23
23
  ActivityTaskCompletion,
24
24
  },
25
25
  temporal::api::{
26
- enums::v1::WorkflowIdReusePolicy, failure::v1::Failure, query::v1::WorkflowQuery,
27
- workflowservice::v1::ListNamespacesRequest,
26
+ enums::v1::WorkflowIdReusePolicy,
27
+ failure::v1::Failure,
28
+ query::v1::WorkflowQuery,
29
+ workflowservice::v1::{DescribeNamespaceRequest, ListNamespacesRequest},
28
30
  },
29
31
  };
30
32
  use temporal_sdk_core_test_utils::{
@@ -34,24 +36,30 @@ use tokio::{join, sync::Barrier, task::AbortHandle};
34
36
 
35
37
  static ANY_PORT: &str = "127.0.0.1:0";
36
38
 
37
- async fn get_text(endpoint: String) -> String {
39
+ pub(crate) async fn get_text(endpoint: String) -> String {
38
40
  reqwest::get(endpoint).await.unwrap().text().await.unwrap()
39
41
  }
40
42
 
41
- struct AbortOnDrop {
43
+ pub(crate) struct AbortOnDrop {
42
44
  ah: AbortHandle,
43
45
  }
46
+
44
47
  impl Drop for AbortOnDrop {
45
48
  fn drop(&mut self) {
46
49
  self.ah.abort();
47
50
  }
48
51
  }
49
52
 
50
- fn prom_metrics() -> (TelemetryOptions, SocketAddr, AbortOnDrop) {
53
+ pub(crate) fn prom_metrics(
54
+ use_seconds: bool,
55
+ show_units: bool,
56
+ ) -> (TelemetryOptions, SocketAddr, AbortOnDrop) {
51
57
  let mut telemopts = get_integ_telem_options();
52
58
  let prom_info = start_prometheus_metric_exporter(
53
59
  PrometheusExporterOptionsBuilder::default()
54
60
  .socket_addr(ANY_PORT.parse().unwrap())
61
+ .use_seconds_for_durations(use_seconds)
62
+ .unit_suffix(show_units)
55
63
  .build()
56
64
  .unwrap(),
57
65
  )
@@ -66,13 +74,14 @@ fn prom_metrics() -> (TelemetryOptions, SocketAddr, AbortOnDrop) {
66
74
  )
67
75
  }
68
76
 
77
+ #[rstest::rstest]
69
78
  #[tokio::test]
70
- async fn prometheus_metrics_exported() {
71
- let (telemopts, addr, _aborter) = prom_metrics();
79
+ async fn prometheus_metrics_exported(#[values(true, false)] use_seconds_latency: bool) {
80
+ let (telemopts, addr, _aborter) = prom_metrics(use_seconds_latency, false);
72
81
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
73
82
  let opts = get_integ_server_options();
74
83
  let mut raw_client = opts
75
- .connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
84
+ .connect_no_namespace(rt.telemetry().get_temporal_metric_meter())
76
85
  .await
77
86
  .unwrap();
78
87
  assert!(raw_client.get_client().capabilities().is_some());
@@ -89,6 +98,17 @@ async fn prometheus_metrics_exported() {
89
98
  assert!(body.contains(
90
99
  "temporal_request_latency_count{operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\"} 1"
91
100
  ));
101
+ if use_seconds_latency {
102
+ assert!(body.contains(
103
+ "temporal_request_latency_bucket{\
104
+ operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\",le=\"0.05\"}"
105
+ ));
106
+ } else {
107
+ assert!(body.contains(
108
+ "temporal_request_latency_bucket{\
109
+ operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\",le=\"50\"}"
110
+ ));
111
+ }
92
112
  // Verify counter names are appropriate (don't end w/ '_total')
93
113
  assert!(body.contains("temporal_request{"));
94
114
  // Verify non-temporal metrics meter does not prefix
@@ -106,7 +126,7 @@ async fn prometheus_metrics_exported() {
106
126
 
107
127
  #[tokio::test]
108
128
  async fn one_slot_worker_reports_available_slot() {
109
- let (telemopts, addr, _aborter) = prom_metrics();
129
+ let (telemopts, addr, _aborter) = prom_metrics(false, false);
110
130
  let tq = "one_slot_worker_tq";
111
131
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
112
132
 
@@ -125,7 +145,7 @@ async fn one_slot_worker_reports_available_slot() {
125
145
 
126
146
  let client = Arc::new(
127
147
  get_integ_server_options()
128
- .connect(worker_cfg.namespace.clone(), None, None)
148
+ .connect(worker_cfg.namespace.clone(), None)
129
149
  .await
130
150
  .expect("Must connect"),
131
151
  );
@@ -235,8 +255,7 @@ async fn one_slot_worker_reports_available_slot() {
235
255
 
236
256
  wf_task_barr.wait().await;
237
257
 
238
- // At this point the workflow task is outstanding, so there should be 0 slots, and
239
- // the activities haven't started, so there should still be 1 each.
258
+ // At this point the workflow task is outstanding and the activities haven't started
240
259
  let body = get_text(format!("http://{addr}/metrics")).await;
241
260
  assert!(body.contains(&format!(
242
261
  "temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
@@ -253,8 +272,23 @@ async fn one_slot_worker_reports_available_slot() {
253
272
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
254
273
  worker_type=\"LocalActivityWorker\"}} 1"
255
274
  )));
275
+ assert!(body.contains(&format!(
276
+ "temporal_worker_task_slots_used{{namespace=\"{NAMESPACE}\",\
277
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
278
+ worker_type=\"WorkflowWorker\"}} 1"
279
+ )));
280
+ assert!(body.contains(&format!(
281
+ "temporal_worker_task_slots_used{{namespace=\"{NAMESPACE}\",\
282
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
283
+ worker_type=\"ActivityWorker\"}} 0"
284
+ )));
285
+ assert!(body.contains(&format!(
286
+ "temporal_worker_task_slots_used{{namespace=\"{NAMESPACE}\",\
287
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
288
+ worker_type=\"LocalActivityWorker\"}} 0"
289
+ )));
256
290
 
257
- // Now we allow the complete to proceed. Once it goes through, there should be 1 WFT slot
291
+ // Now we allow the complete to proceed. Once it goes through, there should be 2 WFT slot
258
292
  // open but 0 activity slots
259
293
  wf_task_barr.wait().await;
260
294
  wf_task_barr.wait().await;
@@ -271,6 +305,11 @@ async fn one_slot_worker_reports_available_slot() {
271
305
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
272
306
  worker_type=\"ActivityWorker\"}} 0"
273
307
  )));
308
+ assert!(body.contains(&format!(
309
+ "temporal_worker_task_slots_used{{namespace=\"{NAMESPACE}\",\
310
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
311
+ worker_type=\"ActivityWorker\"}} 1"
312
+ )));
274
313
 
275
314
  // Now complete the activity and watch it go up
276
315
  act_task_barr.wait().await;
@@ -292,6 +331,11 @@ async fn one_slot_worker_reports_available_slot() {
292
331
  service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
293
332
  worker_type=\"LocalActivityWorker\"}} 0"
294
333
  )));
334
+ assert!(body.contains(&format!(
335
+ "temporal_worker_task_slots_used{{namespace=\"{NAMESPACE}\",\
336
+ service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
337
+ worker_type=\"LocalActivityWorker\"}} 1"
338
+ )));
295
339
  // When completion is done, we have 1 again
296
340
  act_task_barr.wait().await;
297
341
  act_task_barr.wait().await;
@@ -318,12 +362,12 @@ async fn query_of_closed_workflow_doesnt_tick_terminal_metric(
318
362
  )]
319
363
  completion: workflow_command::Variant,
320
364
  ) {
321
- let (telemopts, addr, _aborter) = prom_metrics();
365
+ let (telemopts, addr, _aborter) = prom_metrics(false, false);
322
366
  let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
323
367
  let mut starter =
324
368
  CoreWfStarter::new_with_runtime("query_of_closed_workflow_doesnt_tick_terminal_metric", rt);
325
369
  // Disable cache to ensure replay happens completely
326
- starter.max_cached_workflows(0);
370
+ starter.worker_config.max_cached_workflows(0_usize);
327
371
  let worker = starter.get_worker().await;
328
372
  let run_id = starter.start_wf().await;
329
373
  let task = worker.poll_workflow_activation().await.unwrap();
@@ -447,13 +491,13 @@ fn runtime_new() {
447
491
  .unwrap();
448
492
  let handle = rt.tokio_handle();
449
493
  let _rt = handle.enter();
450
- let (telemopts, addr, _aborter) = prom_metrics();
494
+ let (telemopts, addr, _aborter) = prom_metrics(false, false);
451
495
  rt.telemetry_mut()
452
496
  .attach_late_init_metrics(telemopts.metrics.unwrap());
453
497
  let opts = get_integ_server_options();
454
498
  handle.block_on(async {
455
499
  let mut raw_client = opts
456
- .connect_no_namespace(rt.telemetry().get_temporal_metric_meter(), None)
500
+ .connect_no_namespace(rt.telemetry().get_temporal_metric_meter())
457
501
  .await
458
502
  .unwrap();
459
503
  assert!(raw_client.get_client().capabilities().is_some());
@@ -465,3 +509,68 @@ fn runtime_new() {
465
509
  assert!(body.contains("temporal_request"));
466
510
  });
467
511
  }
512
+
513
+ #[rstest::rstest]
514
+ #[tokio::test]
515
+ async fn latency_metrics(
516
+ #[values(true, false)] use_seconds_latency: bool,
517
+ #[values(true, false)] show_units: bool,
518
+ ) {
519
+ let (telemopts, addr, _aborter) = prom_metrics(use_seconds_latency, show_units);
520
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
521
+ let mut starter = CoreWfStarter::new_with_runtime("latency_metrics", rt);
522
+ let worker = starter.get_worker().await;
523
+ starter.start_wf().await;
524
+ // Immediately finish workflow
525
+ let task = worker.poll_workflow_activation().await.unwrap();
526
+ worker
527
+ .complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
528
+ task.run_id,
529
+ CompleteWorkflowExecution { result: None }.into(),
530
+ ))
531
+ .await
532
+ .unwrap();
533
+
534
+ let body = get_text(format!("http://{addr}/metrics")).await;
535
+ let matching_line = body
536
+ .lines()
537
+ .find(|l| l.starts_with("temporal_workflow_endtoend_latency"))
538
+ .unwrap();
539
+
540
+ if use_seconds_latency {
541
+ if show_units {
542
+ assert!(matching_line.contains("temporal_workflow_endtoend_latency_seconds"));
543
+ }
544
+ assert!(matching_line.contains("le=\"0.1\""));
545
+ } else {
546
+ if show_units {
547
+ assert!(matching_line.contains("temporal_workflow_endtoend_latency_milliseconds"));
548
+ }
549
+ assert!(matching_line.contains("le=\"100\""));
550
+ }
551
+ }
552
+
553
+ #[tokio::test]
554
+ async fn request_fail_codes() {
555
+ let (telemopts, addr, _aborter) = prom_metrics(false, false);
556
+ let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
557
+ let opts = get_integ_server_options();
558
+ let mut client = opts
559
+ .connect(NAMESPACE, rt.telemetry().get_temporal_metric_meter())
560
+ .await
561
+ .unwrap();
562
+
563
+ // Describe namespace w/ invalid argument (unset namespace field)
564
+ WorkflowService::describe_namespace(&mut client, DescribeNamespaceRequest::default())
565
+ .await
566
+ .unwrap_err();
567
+
568
+ let body = get_text(format!("http://{addr}/metrics")).await;
569
+ let matching_line = body
570
+ .lines()
571
+ .find(|l| l.starts_with("temporal_request_failure"))
572
+ .unwrap();
573
+ assert!(matching_line.contains("operation=\"DescribeNamespace\""));
574
+ assert!(matching_line.contains("status_code=\"INVALID_ARGUMENT\""));
575
+ assert!(matching_line.contains("} 1"));
576
+ }