@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,11 +1,14 @@
1
1
  mod activities;
2
2
  pub(crate) mod client;
3
3
  mod slot_provider;
4
+ pub(crate) mod tuner;
4
5
  mod workflow;
5
6
 
6
7
  pub use temporal_sdk_core_api::worker::{WorkerConfig, WorkerConfigBuilder};
7
- #[cfg(feature = "save_wf_inputs")]
8
- pub use workflow::replay_wf_state_inputs;
8
+ pub use tuner::{
9
+ FixedSizeSlotSupplier, RealSysInfo, ResourceBasedSlots, ResourceBasedTuner,
10
+ ResourceSlotOptions, TunerBuilder, TunerHolder,
11
+ };
9
12
 
10
13
  pub(crate) use activities::{
11
14
  ExecutingLAId, LocalActRequest, LocalActivityExecutionResult, LocalActivityResolution,
@@ -13,10 +16,10 @@ pub(crate) use activities::{
13
16
  };
14
17
  pub(crate) use workflow::{wft_poller::new_wft_poller, LEGACY_QUERY_ID};
15
18
 
16
- use temporal_client::WorkerKey;
19
+ use temporal_client::{ConfiguredClient, TemporalServiceClientWithMetrics, WorkerKey};
17
20
 
18
21
  use crate::{
19
- abstractions::{dbg_panic, MeteredSemaphore},
22
+ abstractions::{dbg_panic, MeteredPermitDealer},
20
23
  errors::CompleteWfError,
21
24
  pollers::{
22
25
  new_activity_task_buffer, new_workflow_task_buffer, BoxedActPoller, WorkflowTaskPoller,
@@ -38,6 +41,7 @@ use crate::{
38
41
  };
39
42
  use activities::WorkerActivityTasks;
40
43
  use futures_util::{stream, StreamExt};
44
+ use parking_lot::Mutex;
41
45
  use slot_provider::SlotProvider;
42
46
  use std::{
43
47
  convert::TryInto,
@@ -81,7 +85,7 @@ pub struct Worker {
81
85
  config: WorkerConfig,
82
86
  wf_client: Arc<dyn WorkerClient>,
83
87
  /// Registration key to enable eager workflow start for this worker
84
- worker_key: Option<WorkerKey>,
88
+ worker_key: Mutex<Option<WorkerKey>>,
85
89
  /// Manages all workflows and WFT processing
86
90
  workflows: Workflows,
87
91
  /// Manages activity tasks for this worker/task queue
@@ -169,7 +173,7 @@ impl WorkerTrait for Worker {
169
173
  }
170
174
  self.shutdown_token.cancel();
171
175
  // First, disable Eager Workflow Start
172
- if let Some(key) = self.worker_key {
176
+ if let Some(key) = *self.worker_key.lock() {
173
177
  self.wf_client.workers().unregister(key);
174
178
  }
175
179
  // Second, we want to stop polling of both activity and workflow tasks
@@ -217,12 +221,23 @@ impl Worker {
217
221
  )
218
222
  }
219
223
 
224
+ /// Replace client and return a new client. For eager workflow purposes, this new client will
225
+ /// now apply to future eager start requests and the older client will not.
226
+ pub fn replace_client(&self, new_client: ConfiguredClient<TemporalServiceClientWithMetrics>) {
227
+ // Unregister worker from current client, register in new client at the end
228
+ let mut worker_key = self.worker_key.lock();
229
+ let slot_provider = (*worker_key).and_then(|k| self.wf_client.workers().unregister(k));
230
+ self.wf_client
231
+ .replace_client(super::init_worker_client(&self.config, new_client));
232
+ *worker_key = slot_provider
233
+ .and_then(|slot_provider| self.wf_client.workers().register(slot_provider));
234
+ }
235
+
220
236
  #[cfg(test)]
221
237
  pub(crate) fn new_test(config: WorkerConfig, client: impl WorkerClient + 'static) -> Self {
222
238
  Self::new(config, None, Arc::new(client), None)
223
239
  }
224
240
 
225
- #[allow(clippy::too_many_arguments)] // Not much worth combining here
226
241
  pub(crate) fn new_with_pollers(
227
242
  config: WorkerConfig,
228
243
  sticky_queue_name: Option<String>,
@@ -230,22 +245,40 @@ impl Worker {
230
245
  task_pollers: TaskPollers,
231
246
  telem_instance: Option<&TelemetryInstance>,
232
247
  ) -> Self {
233
- let metrics = if let Some(ti) = telem_instance {
234
- MetricsContext::top_level(config.namespace.clone(), config.task_queue.clone(), ti)
248
+ let (metrics, meter) = if let Some(ti) = telem_instance {
249
+ (
250
+ MetricsContext::top_level(config.namespace.clone(), config.task_queue.clone(), ti),
251
+ ti.get_metric_meter(),
252
+ )
235
253
  } else {
236
- MetricsContext::no_op()
254
+ (MetricsContext::no_op(), None)
237
255
  };
256
+ let tuner = config
257
+ .tuner
258
+ .as_ref()
259
+ .cloned()
260
+ .unwrap_or_else(|| TunerBuilder::from_config(&config).build());
261
+
238
262
  metrics.worker_registered();
263
+ if let Some(meter) = meter {
264
+ tuner.attach_metrics(meter.clone());
265
+ }
239
266
  let shutdown_token = CancellationToken::new();
240
- let wft_semaphore = Arc::new(MeteredSemaphore::new(
241
- config.max_outstanding_workflow_tasks,
267
+ let wft_slots = Arc::new(MeteredPermitDealer::new(
268
+ tuner.workflow_task_slot_supplier(),
242
269
  metrics.with_new_attrs([workflow_worker_type()]),
243
- MetricsContext::available_task_slots,
270
+ if config.max_cached_workflows > 0 {
271
+ // Since we always need to be able to poll the normal task queue as well as the
272
+ // sticky queue, we need a value of at least 2 here.
273
+ Some(std::cmp::max(2, config.max_cached_workflows))
274
+ } else {
275
+ None
276
+ },
244
277
  ));
245
- let act_semaphore = Arc::new(MeteredSemaphore::new(
246
- config.max_outstanding_activities,
278
+ let act_slots = Arc::new(MeteredPermitDealer::new(
279
+ tuner.activity_task_slot_supplier(),
247
280
  metrics.with_new_attrs([activity_worker_type()]),
248
- MetricsContext::available_task_slots,
281
+ None,
249
282
  ));
250
283
  let (external_wft_tx, external_wft_rx) = unbounded_channel();
251
284
  let (wft_stream, act_poller) = match task_pollers {
@@ -265,7 +298,7 @@ impl Worker {
265
298
  normal_name: "".to_string(),
266
299
  },
267
300
  max_nonsticky_polls,
268
- wft_semaphore.clone(),
301
+ wft_slots.clone(),
269
302
  shutdown_token.child_token(),
270
303
  Some(move |np| {
271
304
  wft_metrics.record_num_pollers(np);
@@ -281,7 +314,7 @@ impl Worker {
281
314
  normal_name: config.task_queue.clone(),
282
315
  },
283
316
  max_sticky_polls,
284
- wft_semaphore.clone(),
317
+ wft_slots.clone(),
285
318
  shutdown_token.child_token(),
286
319
  Some(move |np| {
287
320
  sticky_metrics.record_num_pollers(np);
@@ -296,7 +329,7 @@ impl Worker {
296
329
  client.clone(),
297
330
  config.task_queue.clone(),
298
331
  config.max_concurrent_at_polls,
299
- act_semaphore.clone(),
332
+ act_slots.clone(),
300
333
  config.max_task_queue_activities_per_second,
301
334
  shutdown_token.child_token(),
302
335
  Some(move |np| act_metrics.record_num_pollers(np)),
@@ -327,9 +360,8 @@ impl Worker {
327
360
  wft_stream,
328
361
  act_poller,
329
362
  } => {
330
- let ap =
331
- act_poller.map(|ap| MockPermittedPollBuffer::new(act_semaphore.clone(), ap));
332
- let wft_semaphore = wft_semaphore.clone();
363
+ let ap = act_poller.map(|ap| MockPermittedPollBuffer::new(act_slots.clone(), ap));
364
+ let wft_semaphore = wft_slots.clone();
333
365
  let wfs = wft_stream.then(move |s| {
334
366
  let wft_semaphore = wft_semaphore.clone();
335
367
  async move {
@@ -347,14 +379,14 @@ impl Worker {
347
379
 
348
380
  let (hb_tx, hb_rx) = unbounded_channel();
349
381
  let local_act_mgr = Arc::new(LocalActivityManager::new(
350
- config.max_outstanding_local_activities,
382
+ tuner.local_activity_slot_supplier(),
351
383
  config.namespace.clone(),
352
384
  hb_tx,
353
385
  metrics.with_new_attrs([local_activity_worker_type()]),
354
386
  ));
355
387
  let at_task_mgr = act_poller.map(|ap| {
356
388
  WorkerActivityTasks::new(
357
- act_semaphore,
389
+ act_slots,
358
390
  ap,
359
391
  client.clone(),
360
392
  metrics.clone(),
@@ -368,14 +400,14 @@ impl Worker {
368
400
  if !poll_on_non_local_activities {
369
401
  info!("Activity polling is disabled for this worker");
370
402
  };
371
- let la_sink = LAReqSink::new(local_act_mgr.clone(), config.wf_state_inputs.clone());
403
+ let la_sink = LAReqSink::new(local_act_mgr.clone());
372
404
  let provider = SlotProvider::new(
373
405
  config.namespace.clone(),
374
406
  config.task_queue.clone(),
375
- wft_semaphore.clone(),
407
+ wft_slots.clone(),
376
408
  external_wft_tx,
377
409
  );
378
- let worker_key = client.workers().register(Box::new(provider));
410
+ let worker_key = Mutex::new(client.workers().register(Box::new(provider)));
379
411
  Self {
380
412
  worker_key,
381
413
  wf_client: client.clone(),
@@ -384,7 +416,7 @@ impl Worker {
384
416
  config.clone(),
385
417
  metrics,
386
418
  shutdown_token.child_token(),
387
- client.capabilities().cloned().unwrap_or_default(),
419
+ client.capabilities().clone().unwrap_or_default(),
388
420
  ),
389
421
  sticky_queue_name.map(|sq| StickyExecutionAttributes {
390
422
  worker_task_queue: Some(TaskQueue {
@@ -400,7 +432,7 @@ impl Worker {
400
432
  ),
401
433
  }),
402
434
  client,
403
- wft_semaphore,
435
+ wft_slots,
404
436
  wft_stream,
405
437
  la_sink,
406
438
  local_act_mgr.clone(),
@@ -473,11 +505,11 @@ impl Worker {
473
505
  }
474
506
 
475
507
  #[allow(unused)]
476
- pub(crate) fn available_wft_permits(&self) -> usize {
508
+ pub(crate) fn available_wft_permits(&self) -> Option<usize> {
477
509
  self.workflows.available_wft_permits()
478
510
  }
479
511
  #[cfg(test)]
480
- pub(crate) fn unused_wft_permits(&self) -> usize {
512
+ pub(crate) fn unused_wft_permits(&self) -> Option<usize> {
481
513
  self.workflows.unused_wft_permits()
482
514
  }
483
515
 
@@ -659,10 +691,9 @@ impl Worker {
659
691
  }
660
692
  }
661
693
 
662
- pub struct PostActivateHookData<'a> {
663
- pub run_id: &'a str,
664
- pub most_recent_event: usize,
665
- pub replaying: bool,
694
+ pub(crate) struct PostActivateHookData<'a> {
695
+ pub(crate) run_id: &'a str,
696
+ pub(crate) replaying: bool,
666
697
  }
667
698
 
668
699
  fn build_wf_basics(
@@ -718,7 +749,7 @@ mod tests {
718
749
  .as_ref()
719
750
  .unwrap()
720
751
  .remaining_activity_capacity(),
721
- 5
752
+ Some(5)
722
753
  );
723
754
  }
724
755
 
@@ -735,16 +766,15 @@ mod tests {
735
766
  .unwrap();
736
767
  let worker = Worker::new_test(cfg, mock_client);
737
768
  assert!(worker.activity_poll().await.is_err());
738
- assert_eq!(worker.at_task_mgr.unwrap().remaining_activity_capacity(), 5);
769
+ assert_eq!(
770
+ worker.at_task_mgr.unwrap().remaining_activity_capacity(),
771
+ Some(5)
772
+ );
739
773
  }
740
774
 
741
775
  #[test]
742
776
  fn max_polls_calculated_properly() {
743
- let mut wcb = WorkerConfigBuilder::default();
744
- let cfg = wcb
745
- .namespace("default")
746
- .task_queue("whatever")
747
- .worker_build_id("test_bin_id")
777
+ let cfg = test_worker_cfg()
748
778
  .max_concurrent_wft_polls(5_usize)
749
779
  .build()
750
780
  .unwrap();
@@ -3,27 +3,38 @@
3
3
  //! This enables latency optimizations such as Eager Workflow Start.
4
4
 
5
5
  use crate::{
6
- abstractions::{MeteredSemaphore, OwnedMeteredSemPermit},
6
+ abstractions::{MeteredPermitDealer, OwnedMeteredSemPermit},
7
7
  protosext::ValidPollWFTQResponse,
8
8
  worker::workflow::wft_poller::validate_wft,
9
9
  };
10
10
 
11
11
  use std::sync::Arc;
12
12
  use temporal_client::{Slot as SlotTrait, SlotProvider as SlotProviderTrait};
13
+ use temporal_sdk_core_api::worker::WorkflowSlotKind;
13
14
  use temporal_sdk_core_protos::temporal::api::workflowservice::v1::PollWorkflowTaskQueueResponse;
14
15
  use tokio::sync::mpsc::UnboundedSender;
15
16
  use tonic::Status;
16
17
 
17
- type WFTStreamSender =
18
- UnboundedSender<Result<(ValidPollWFTQResponse, OwnedMeteredSemPermit), Status>>;
19
-
20
- pub struct Slot {
21
- permit: OwnedMeteredSemPermit,
18
+ type WFTStreamSender = UnboundedSender<
19
+ Result<
20
+ (
21
+ ValidPollWFTQResponse,
22
+ OwnedMeteredSemPermit<WorkflowSlotKind>,
23
+ ),
24
+ Status,
25
+ >,
26
+ >;
27
+
28
+ struct Slot {
29
+ permit: OwnedMeteredSemPermit<WorkflowSlotKind>,
22
30
  external_wft_tx: WFTStreamSender,
23
31
  }
24
32
 
25
33
  impl Slot {
26
- fn new(permit: OwnedMeteredSemPermit, external_wft_tx: WFTStreamSender) -> Self {
34
+ fn new(
35
+ permit: OwnedMeteredSemPermit<WorkflowSlotKind>,
36
+ external_wft_tx: WFTStreamSender,
37
+ ) -> Self {
27
38
  Self {
28
39
  permit,
29
40
  external_wft_tx,
@@ -44,18 +55,18 @@ impl SlotTrait for Slot {
44
55
 
45
56
  #[derive(derive_more::DebugCustom)]
46
57
  #[debug(fmt = "SlotProvider {{ namespace:{namespace}, task_queue: {task_queue} }}")]
47
- pub struct SlotProvider {
58
+ pub(super) struct SlotProvider {
48
59
  namespace: String,
49
60
  task_queue: String,
50
- wft_semaphore: Arc<MeteredSemaphore>,
61
+ wft_semaphore: Arc<MeteredPermitDealer<WorkflowSlotKind>>,
51
62
  external_wft_tx: WFTStreamSender,
52
63
  }
53
64
 
54
65
  impl SlotProvider {
55
- pub(crate) fn new(
66
+ pub(super) fn new(
56
67
  namespace: String,
57
68
  task_queue: String,
58
- wft_semaphore: Arc<MeteredSemaphore>,
69
+ wft_semaphore: Arc<MeteredPermitDealer<WorkflowSlotKind>>,
59
70
  external_wft_tx: WFTStreamSender,
60
71
  ) -> Self {
61
72
  Self {
@@ -86,6 +97,7 @@ impl SlotProviderTrait for SlotProvider {
86
97
  mod tests {
87
98
  use super::*;
88
99
 
100
+ use crate::abstractions::tests::fixed_size_permit_dealer;
89
101
  use temporal_sdk_core_protos::temporal::api::{
90
102
  common::v1::{WorkflowExecution, WorkflowType},
91
103
  history::v1::History,
@@ -106,11 +118,7 @@ mod tests {
106
118
 
107
119
  #[tokio::test]
108
120
  async fn slot_propagates_through_channel() {
109
- let wft_semaphore = Arc::new(MeteredSemaphore::new(
110
- 2,
111
- crate::MetricsContext::no_op(),
112
- |_, _| {},
113
- ));
121
+ let wft_semaphore = Arc::new(fixed_size_permit_dealer(2));
114
122
  let (external_wft_tx, mut external_wft_rx) = unbounded_channel();
115
123
 
116
124
  let provider = SlotProvider::new(
@@ -133,11 +141,7 @@ mod tests {
133
141
  let (external_wft_tx, mut external_wft_rx) = unbounded_channel();
134
142
  {
135
143
  let external_wft_tx = external_wft_tx;
136
- let wft_semaphore = Arc::new(MeteredSemaphore::new(
137
- 2,
138
- crate::MetricsContext::no_op(),
139
- |_, _| {},
140
- ));
144
+ let wft_semaphore = Arc::new(fixed_size_permit_dealer(2));
141
145
  let provider = SlotProvider::new(
142
146
  "my_namespace".to_string(),
143
147
  "my_queue".to_string(),
@@ -151,11 +155,7 @@ mod tests {
151
155
 
152
156
  #[tokio::test]
153
157
  async fn unused_slots_reclaimed() {
154
- let wft_semaphore = Arc::new(MeteredSemaphore::new(
155
- 2,
156
- crate::MetricsContext::no_op(),
157
- |_, _| {},
158
- ));
158
+ let wft_semaphore = Arc::new(fixed_size_permit_dealer(2));
159
159
  {
160
160
  let wft_semaphore = wft_semaphore.clone();
161
161
  let (external_wft_tx, _) = unbounded_channel();
@@ -167,9 +167,9 @@ mod tests {
167
167
  );
168
168
  let slot = provider.try_reserve_wft_slot();
169
169
  assert!(slot.is_some());
170
- assert_eq!(wft_semaphore.available_permits(), 1);
170
+ assert_eq!(wft_semaphore.available_permits(), Some(1));
171
171
  // drop slot without using it
172
172
  }
173
- assert_eq!(wft_semaphore.available_permits(), 2);
173
+ assert_eq!(wft_semaphore.available_permits(), Some(2));
174
174
  }
175
175
  }
@@ -0,0 +1,52 @@
1
+ use std::{marker::PhantomData, sync::Arc};
2
+ use temporal_sdk_core_api::worker::{
3
+ SlotKind, SlotReservationContext, SlotSupplier, SlotSupplierPermit,
4
+ };
5
+ use tokio::sync::Semaphore;
6
+
7
+ /// Implements [SlotSupplier] with a fixed number of slots
8
+ pub struct FixedSizeSlotSupplier<SK> {
9
+ sem: Arc<Semaphore>,
10
+ _pd: PhantomData<SK>,
11
+ }
12
+
13
+ impl<SK> FixedSizeSlotSupplier<SK> {
14
+ /// Create a slot supplier which will only hand out at most the provided number of slots
15
+ pub fn new(size: usize) -> Self {
16
+ Self {
17
+ sem: Arc::new(Semaphore::new(size)),
18
+ _pd: Default::default(),
19
+ }
20
+ }
21
+ }
22
+
23
+ #[async_trait::async_trait]
24
+ impl<SK> SlotSupplier for FixedSizeSlotSupplier<SK>
25
+ where
26
+ SK: SlotKind + Send + Sync,
27
+ {
28
+ type SlotKind = SK;
29
+
30
+ async fn reserve_slot(&self, _: &dyn SlotReservationContext) -> SlotSupplierPermit {
31
+ let perm = self
32
+ .sem
33
+ .clone()
34
+ .acquire_owned()
35
+ .await
36
+ .expect("inner semaphore is never closed");
37
+ SlotSupplierPermit::with_user_data(perm)
38
+ }
39
+
40
+ fn try_reserve_slot(&self, _: &dyn SlotReservationContext) -> Option<SlotSupplierPermit> {
41
+ let perm = self.sem.clone().try_acquire_owned();
42
+ perm.ok().map(SlotSupplierPermit::with_user_data)
43
+ }
44
+
45
+ fn mark_slot_used(&self, _info: SK::Info<'_>) {}
46
+
47
+ fn release_slot(&self) {}
48
+
49
+ fn available_slots(&self) -> Option<usize> {
50
+ Some(self.sem.available_permits())
51
+ }
52
+ }