@temporalio/core-bridge 1.15.0 → 1.16.1

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 (209) hide show
  1. package/Cargo.lock +172 -70
  2. package/lib/native.d.ts +1 -1
  3. package/package.json +2 -2
  4. package/releases/aarch64-apple-darwin/index.node +0 -0
  5. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  6. package/releases/x86_64-apple-darwin/index.node +0 -0
  7. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  8. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  9. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  10. package/sdk-core/AGENTS.md +41 -30
  11. package/sdk-core/Cargo.toml +3 -0
  12. package/sdk-core/README.md +15 -9
  13. package/sdk-core/crates/client/Cargo.toml +4 -0
  14. package/sdk-core/crates/client/README.md +139 -0
  15. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  16. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  17. package/sdk-core/crates/client/src/errors.rs +294 -0
  18. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +280 -159
  19. package/sdk-core/crates/client/src/lib.rs +920 -1326
  20. package/sdk-core/crates/client/src/metrics.rs +24 -33
  21. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  22. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  23. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  24. package/sdk-core/crates/client/src/retry.rs +99 -54
  25. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +1 -1
  26. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  27. package/sdk-core/crates/common/Cargo.toml +61 -2
  28. package/sdk-core/crates/common/build.rs +742 -12
  29. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  30. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  31. package/sdk-core/crates/common/protos/api_upstream/buf.yaml +0 -3
  32. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  33. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +1166 -770
  34. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +1243 -750
  35. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +2 -2
  36. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -3
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +4 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +16 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -6
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +88 -33
  43. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +4 -2
  44. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  45. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +5 -5
  46. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  47. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  48. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  49. package/sdk-core/crates/common/src/lib.rs +15 -211
  50. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  51. package/sdk-core/crates/common/src/priority.rs +110 -0
  52. package/sdk-core/crates/common/src/protos/canned_histories.rs +3 -0
  53. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  54. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  55. package/sdk-core/crates/common/src/protos/mod.rs +122 -27
  56. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  57. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  58. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +5 -7
  59. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  60. package/sdk-core/crates/common/src/telemetry/metrics.rs +268 -223
  61. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  62. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  63. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  64. package/sdk-core/crates/common/src/telemetry.rs +264 -4
  65. package/sdk-core/crates/common/src/worker.rs +68 -603
  66. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  67. package/sdk-core/crates/macros/Cargo.toml +5 -1
  68. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  69. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  70. package/sdk-core/crates/macros/src/lib.rs +138 -512
  71. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  72. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  73. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  74. package/sdk-core/crates/sdk/README.md +415 -0
  75. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  76. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  77. package/sdk-core/crates/sdk/src/lib.rs +757 -442
  78. package/sdk-core/crates/sdk/src/workflow_context/options.rs +45 -35
  79. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  80. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  81. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  82. package/sdk-core/crates/sdk-core/Cargo.toml +57 -64
  83. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +41 -35
  84. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  85. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  86. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  87. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +13 -15
  88. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  89. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  90. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  91. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +493 -26
  92. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +4 -8
  93. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +7 -7
  94. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  95. package/sdk-core/crates/sdk-core/src/lib.rs +41 -111
  96. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  97. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +118 -19
  98. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  99. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  100. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +179 -196
  101. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -280
  102. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +6 -9
  103. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  104. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  105. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  106. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +9 -5
  107. package/sdk-core/crates/sdk-core/src/worker/client.rs +103 -81
  108. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +7 -11
  109. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1124 -229
  110. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +145 -23
  111. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  112. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  113. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +13 -13
  114. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +28 -8
  115. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  116. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  117. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +19 -4
  118. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +14 -18
  119. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +4 -6
  120. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  121. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  122. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  123. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  124. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  125. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  126. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  127. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  128. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  129. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  130. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  131. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  132. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  133. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  134. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  135. package/sdk-core/crates/sdk-core/tests/common/mod.rs +241 -196
  136. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  137. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +3 -5
  138. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -64
  139. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +298 -252
  140. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  141. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  142. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  143. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +16 -12
  144. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +48 -40
  145. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +327 -255
  146. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  147. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +147 -126
  148. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  149. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -453
  150. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  151. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +360 -231
  152. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +248 -185
  153. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -43
  154. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  155. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +428 -315
  156. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -56
  157. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -28
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -243
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +101 -42
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -147
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -28
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1036
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -41
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +397 -238
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +414 -189
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +154 -137
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -105
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -38
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -40
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -54
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +363 -226
  175. package/sdk-core/crates/sdk-core/tests/main.rs +17 -15
  176. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +207 -152
  177. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +65 -34
  178. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  179. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  180. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  181. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  182. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  183. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  184. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  185. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  186. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  187. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  188. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +7 -1
  189. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +14 -14
  190. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +83 -74
  191. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +9 -14
  192. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +1 -2
  193. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +13 -13
  194. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +6 -6
  195. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +3 -4
  196. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +62 -75
  197. package/sdk-core/rustfmt.toml +2 -1
  198. package/src/client.rs +205 -318
  199. package/src/metrics.rs +22 -30
  200. package/src/runtime.rs +4 -5
  201. package/src/worker.rs +16 -19
  202. package/ts/native.ts +1 -1
  203. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  204. package/sdk-core/crates/common/src/errors.rs +0 -85
  205. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  206. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  207. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  208. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  209. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -1,22 +1,15 @@
1
1
  //! Contains types that are needed by both the client and the sdk when configuring / interacting
2
2
  //! with workers.
3
3
 
4
- use crate::{
5
- errors::WorkflowErrorType,
6
- protos::{
7
- coresdk,
8
- coresdk::{ActivitySlotInfo, LocalActivitySlotInfo, NexusSlotInfo, WorkflowSlotInfo},
9
- temporal,
10
- temporal::api::{enums::v1::VersioningBehavior, worker::v1::PluginInfo},
11
- },
12
- telemetry::metrics::TemporalMeter,
4
+ use crate::protos::{
5
+ coresdk, temporal,
6
+ temporal::api::enums::v1::{TaskQueueType, VersioningBehavior},
13
7
  };
14
8
  use std::{
15
- any::Any,
16
- collections::{HashMap, HashSet},
9
+ fs::File,
10
+ io::{self, BufReader, Read},
17
11
  str::FromStr,
18
- sync::Arc,
19
- time::Duration,
12
+ sync::OnceLock,
20
13
  };
21
14
 
22
15
  /// Specifies which task types a worker will poll for.
@@ -24,9 +17,13 @@ use std::{
24
17
  /// Workers can be configured to handle any combination of workflows, activities, and nexus operations.
25
18
  #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26
19
  pub struct WorkerTaskTypes {
20
+ /// Whether workflow tasks are enabled.
27
21
  pub enable_workflows: bool,
22
+ /// Whether local activity tasks are enabled.
28
23
  pub enable_local_activities: bool,
24
+ /// Whether remote activity tasks are enabled.
29
25
  pub enable_remote_activities: bool,
26
+ /// Whether nexus tasks are enabled.
30
27
  pub enable_nexus: bool,
31
28
  }
32
29
 
@@ -79,609 +76,31 @@ impl WorkerTaskTypes {
79
76
  }
80
77
  }
81
78
 
79
+ /// Returns true if any task type is enabled in both configs.
82
80
  pub fn overlaps_with(&self, other: &WorkerTaskTypes) -> bool {
83
81
  (self.enable_workflows && other.enable_workflows)
84
82
  || (self.enable_local_activities && other.enable_local_activities)
85
83
  || (self.enable_remote_activities && other.enable_remote_activities)
86
84
  || (self.enable_nexus && other.enable_nexus)
87
85
  }
88
- }
89
-
90
- /// Defines per-worker configuration options
91
- #[derive(Clone, bon::Builder)]
92
- #[builder(on(String, into), state_mod(vis = "pub"), finish_fn(vis = "", name = build_internal))]
93
- #[non_exhaustive]
94
- pub struct WorkerConfig {
95
- /// The Temporal service namespace this worker is bound to
96
- pub namespace: String,
97
- /// What task queue will this worker poll from? This task queue name will be used for both
98
- /// workflow and activity polling.
99
- pub task_queue: String,
100
- /// A human-readable string that can identify this worker. Using something like sdk version
101
- /// and host name is a good default. If set, overrides the identity set (if any) on the client
102
- /// used by this worker.
103
- pub client_identity_override: Option<String>,
104
- /// If set nonzero, workflows will be cached and sticky task queues will be used, meaning that
105
- /// history updates are applied incrementally to suspended instances of workflow execution.
106
- /// Workflows are evicted according to a least-recently-used policy one the cache maximum is
107
- /// reached. Workflows may also be explicitly evicted at any time, or as a result of errors
108
- /// or failures.
109
- #[builder(default = 0)]
110
- pub max_cached_workflows: usize,
111
- /// Set a [WorkerTuner] for this worker. Either this or at least one of the `max_outstanding_*`
112
- /// fields must be set.
113
- pub tuner: Option<Arc<dyn WorkerTuner + Send + Sync>>,
114
- /// Maximum number of concurrent poll workflow task requests we will perform at a time on this
115
- /// worker's task queue. See also [WorkerConfig::nonsticky_to_sticky_poll_ratio].
116
- /// If using SimpleMaximum, Must be at least 2 when `max_cached_workflows` > 0, or is an error.
117
- #[builder(default = PollerBehavior::SimpleMaximum(5))]
118
- pub workflow_task_poller_behavior: PollerBehavior,
119
- /// Only applies when using [PollerBehavior::SimpleMaximum]
120
- ///
121
- /// (max workflow task polls * this number) = the number of max pollers that will be allowed for
122
- /// the nonsticky queue when sticky tasks are enabled. If both defaults are used, the sticky
123
- /// queue will allow 4 max pollers while the nonsticky queue will allow one. The minimum for
124
- /// either poller is 1, so if the maximum allowed is 1 and sticky queues are enabled, there will
125
- /// be 2 concurrent polls.
126
- #[builder(default = 0.2)]
127
- pub nonsticky_to_sticky_poll_ratio: f32,
128
- /// Maximum number of concurrent poll activity task requests we will perform at a time on this
129
- /// worker's task queue
130
- #[builder(default = PollerBehavior::SimpleMaximum(5))]
131
- pub activity_task_poller_behavior: PollerBehavior,
132
- /// Maximum number of concurrent poll nexus task requests we will perform at a time on this
133
- /// worker's task queue
134
- #[builder(default = PollerBehavior::SimpleMaximum(5))]
135
- pub nexus_task_poller_behavior: PollerBehavior,
136
- /// Specifies which task types this worker will poll for.
137
- ///
138
- /// Note: At least one task type must be specified or the worker will fail validation.
139
- pub task_types: WorkerTaskTypes,
140
- /// How long a workflow task is allowed to sit on the sticky queue before it is timed out
141
- /// and moved to the non-sticky queue where it may be picked up by any worker.
142
- #[builder(default = Duration::from_secs(10))]
143
- pub sticky_queue_schedule_to_start_timeout: Duration,
144
-
145
- /// Longest interval for throttling activity heartbeats
146
- #[builder(default = Duration::from_secs(60))]
147
- pub max_heartbeat_throttle_interval: Duration,
148
-
149
- /// Default interval for throttling activity heartbeats in case
150
- /// `ActivityOptions.heartbeat_timeout` is unset.
151
- /// When the timeout *is* set in the `ActivityOptions`, throttling is set to
152
- /// `heartbeat_timeout * 0.8`.
153
- #[builder(default = Duration::from_secs(30))]
154
- pub default_heartbeat_throttle_interval: Duration,
155
-
156
- /// Sets the maximum number of activities per second the task queue will dispatch, controlled
157
- /// server-side. Note that this only takes effect upon an activity poll request. If multiple
158
- /// workers on the same queue have different values set, they will thrash with the last poller
159
- /// winning.
160
- ///
161
- /// Setting this to a nonzero value will also disable eager activity execution.
162
- pub max_task_queue_activities_per_second: Option<f64>,
163
-
164
- /// Limits the number of activities per second that this worker will process. The worker will
165
- /// not poll for new activities if by doing so it might receive and execute an activity which
166
- /// would cause it to exceed this limit. Negative, zero, or NaN values will cause building
167
- /// the options to fail.
168
- pub max_worker_activities_per_second: Option<f64>,
169
-
170
- /// If set false (default), shutdown will not finish until all pending evictions have been
171
- /// issued and replied to. If set true shutdown will be considered complete when the only
172
- /// remaining work is pending evictions.
173
- ///
174
- /// This flag is useful during tests to avoid needing to deal with lots of uninteresting
175
- /// evictions during shutdown. Alternatively, if a lang implementation finds it easy to clean
176
- /// up during shutdown, setting this true saves some back-and-forth.
177
- #[builder(default = false)]
178
- pub ignore_evicts_on_shutdown: bool,
179
-
180
- /// Maximum number of next page (or initial) history event listing requests we'll make
181
- /// concurrently. I don't this it's worth exposing this to users until we encounter a reason.
182
- #[builder(default = 5)]
183
- pub fetching_concurrency: usize,
184
-
185
- /// If set, core will issue cancels for all outstanding activities and nexus operations after
186
- /// shutdown has been initiated and this amount of time has elapsed.
187
- pub graceful_shutdown_period: Option<Duration>,
188
-
189
- /// The amount of time core will wait before timing out activities using its own local timers
190
- /// after one of them elapses. This is to avoid racing with server's own tracking of the
191
- /// timeout.
192
- #[builder(default = Duration::from_secs(5))]
193
- pub local_timeout_buffer_for_activities: Duration,
194
-
195
- /// Any error types listed here will cause any workflow being processed by this worker to fail,
196
- /// rather than simply failing the workflow task.
197
- #[builder(default)]
198
- pub workflow_failure_errors: HashSet<WorkflowErrorType>,
199
-
200
- /// Like [WorkerConfig::workflow_failure_errors], but specific to certain workflow types (the
201
- /// map key).
202
- #[builder(default)]
203
- pub workflow_types_to_failure_errors: HashMap<String, HashSet<WorkflowErrorType>>,
204
-
205
- /// The maximum allowed number of workflow tasks that will ever be given to this worker at one
206
- /// time. Note that one workflow task may require multiple activations - so the WFT counts as
207
- /// "outstanding" until all activations it requires have been completed. Must be at least 2 if
208
- /// `max_cached_workflows` is > 0, or is an error.
209
- ///
210
- /// Mutually exclusive with `tuner`
211
- #[builder(into)]
212
- pub max_outstanding_workflow_tasks: Option<usize>,
213
- /// The maximum number of activity tasks that will ever be given to this worker concurrently.
214
- ///
215
- /// Mutually exclusive with `tuner`
216
- #[builder(into)]
217
- pub max_outstanding_activities: Option<usize>,
218
- /// The maximum number of local activity tasks that will ever be given to this worker
219
- /// concurrently.
220
- ///
221
- /// Mutually exclusive with `tuner`
222
- #[builder(into)]
223
- pub max_outstanding_local_activities: Option<usize>,
224
- /// The maximum number of nexus tasks that will ever be given to this worker
225
- /// concurrently.
226
- ///
227
- /// Mutually exclusive with `tuner`
228
- #[builder(into)]
229
- pub max_outstanding_nexus_tasks: Option<usize>,
230
-
231
- /// A versioning strategy for this worker.
232
- pub versioning_strategy: WorkerVersioningStrategy,
233
-
234
- /// List of plugins used by lang.
235
- #[builder(default)]
236
- pub plugins: HashSet<PluginInfo>,
237
-
238
- /// Skips the single worker+client+namespace+task_queue check
239
- #[builder(default = false)]
240
- pub skip_client_worker_set_check: bool,
241
- }
242
-
243
- impl WorkerConfig {
244
- /// Returns true if the configuration specifies we should fail a workflow on a certain error
245
- /// type rather than failing the workflow task.
246
- pub fn should_fail_workflow(
247
- &self,
248
- workflow_type: &str,
249
- error_type: &WorkflowErrorType,
250
- ) -> bool {
251
- self.workflow_failure_errors.contains(error_type)
252
- || self
253
- .workflow_types_to_failure_errors
254
- .get(workflow_type)
255
- .map(|s| s.contains(error_type))
256
- .unwrap_or(false)
257
- }
258
-
259
- pub fn computed_deployment_version(&self) -> Option<WorkerDeploymentVersion> {
260
- let wdv = match self.versioning_strategy {
261
- WorkerVersioningStrategy::None { ref build_id } => WorkerDeploymentVersion {
262
- deployment_name: "".to_owned(),
263
- build_id: build_id.clone(),
264
- },
265
- WorkerVersioningStrategy::WorkerDeploymentBased(ref opts) => opts.version.clone(),
266
- WorkerVersioningStrategy::LegacyBuildIdBased { ref build_id } => {
267
- WorkerDeploymentVersion {
268
- deployment_name: "".to_owned(),
269
- build_id: build_id.clone(),
270
- }
271
- }
272
- };
273
- if wdv.is_empty() { None } else { Some(wdv) }
274
- }
275
- }
276
-
277
- impl<S: worker_config_builder::IsComplete> WorkerConfigBuilder<S> {
278
- pub fn build(self) -> Result<WorkerConfig, String> {
279
- let config = self.build_internal();
280
- let task_types = &config.task_types;
281
- if task_types.is_empty() {
282
- return Err("At least one task type must be enabled in `task_types`".to_string());
283
- }
284
- if !task_types.enable_workflows && task_types.enable_local_activities {
285
- return Err(
286
- "`task_types` cannot enable local activities without workflows".to_string(),
287
- );
288
- }
289
-
290
- config.workflow_task_poller_behavior.validate()?;
291
- config.activity_task_poller_behavior.validate()?;
292
- config.nexus_task_poller_behavior.validate()?;
293
-
294
- if let Some(ref x) = config.max_worker_activities_per_second
295
- && (!x.is_normal() || x.is_sign_negative())
296
- {
297
- return Err(
298
- "`max_worker_activities_per_second` must be positive and nonzero".to_string(),
299
- );
300
- }
301
-
302
- if matches!(config.max_outstanding_workflow_tasks, Some(v) if v == 0) {
303
- return Err("`max_outstanding_workflow_tasks` must be > 0".to_string());
304
- }
305
- if matches!(config.max_outstanding_activities, Some(v) if v == 0) {
306
- return Err("`max_outstanding_activities` must be > 0".to_string());
307
- }
308
- if matches!(config.max_outstanding_local_activities, Some(v) if v == 0) {
309
- return Err("`max_outstanding_local_activities` must be > 0".to_string());
310
- }
311
- if matches!(config.max_outstanding_nexus_tasks, Some(v) if v == 0) {
312
- return Err("`max_outstanding_nexus_tasks` must be > 0".to_string());
313
- }
314
-
315
- if config.max_cached_workflows > 0 {
316
- if let Some(max_wft) = config.max_outstanding_workflow_tasks
317
- && max_wft < 2
318
- {
319
- return Err(
320
- "`max_cached_workflows` > 0 requires `max_outstanding_workflow_tasks` >= 2"
321
- .to_string(),
322
- );
323
- }
324
- if matches!(config.workflow_task_poller_behavior, PollerBehavior::SimpleMaximum(u) if u < 2)
325
- {
326
- return Err("`max_cached_workflows` > 0 requires `workflow_task_poller_behavior` to be at least 2".to_string());
327
- }
328
- }
329
-
330
- if config.tuner.is_some()
331
- && (config.max_outstanding_workflow_tasks.is_some()
332
- || config.max_outstanding_activities.is_some()
333
- || config.max_outstanding_local_activities.is_some())
334
- {
335
- return Err("max_outstanding_* fields are mutually exclusive with `tuner`".to_string());
336
- }
337
-
338
- match &config.versioning_strategy {
339
- WorkerVersioningStrategy::None { .. } => {}
340
- WorkerVersioningStrategy::WorkerDeploymentBased(d) => {
341
- if d.use_worker_versioning
342
- && (d.version.build_id.is_empty() || d.version.deployment_name.is_empty())
343
- {
344
- return Err("WorkerDeploymentVersion must have a non-empty build_id and deployment_name when deployment-based versioning is enabled".to_string());
345
- }
346
- }
347
- WorkerVersioningStrategy::LegacyBuildIdBased { build_id } => {
348
- if build_id.is_empty() {
349
- return Err(
350
- "Legacy build id-based versioning must have a non-empty build_id"
351
- .to_string(),
352
- );
353
- }
354
- }
355
- }
356
-
357
- Ok(config)
358
- }
359
- }
360
-
361
- /// This trait allows users to customize the performance characteristics of workers dynamically.
362
- /// For more, see the docstrings of the traits in the return types of its functions.
363
- pub trait WorkerTuner {
364
- /// Return a [SlotSupplier] for workflow tasks. Note that workflow task slot suppliers must be
365
- /// willing to hand out a minimum of one non-sticky slot and one sticky slot if workflow caching
366
- /// is enabled, otherwise the worker may fail to process new tasks.
367
- fn workflow_task_slot_supplier(
368
- &self,
369
- ) -> Arc<dyn SlotSupplier<SlotKind = WorkflowSlotKind> + Send + Sync>;
370
-
371
- /// Return a [SlotSupplier] for activity tasks
372
- fn activity_task_slot_supplier(
373
- &self,
374
- ) -> Arc<dyn SlotSupplier<SlotKind = ActivitySlotKind> + Send + Sync>;
375
-
376
- /// Return a [SlotSupplier] for local activities
377
- fn local_activity_slot_supplier(
378
- &self,
379
- ) -> Arc<dyn SlotSupplier<SlotKind = LocalActivitySlotKind> + Send + Sync>;
380
-
381
- /// Return a [SlotSupplier] for nexus tasks
382
- fn nexus_task_slot_supplier(
383
- &self,
384
- ) -> Arc<dyn SlotSupplier<SlotKind = NexusSlotKind> + Send + Sync>;
385
- }
386
-
387
- /// Implementing this trait allows users to customize how many tasks of certain kinds the worker
388
- /// will perform concurrently.
389
- ///
390
- /// Note that, for implementations on workflow tasks ([WorkflowSlotKind]), workers that have the
391
- /// workflow cache enabled should be willing to hand out _at least_ two slots, to avoid the worker
392
- /// becoming stuck only polling on the worker's sticky queue.
393
- #[async_trait::async_trait]
394
- pub trait SlotSupplier {
395
- type SlotKind: SlotKind;
396
- /// Block until a slot is available, then return a permit for the slot.
397
- async fn reserve_slot(&self, ctx: &dyn SlotReservationContext) -> SlotSupplierPermit;
398
-
399
- /// Try to immediately reserve a slot, returning None if one is not available. Implementations
400
- /// must not block, or risk blocking the async event loop.
401
- fn try_reserve_slot(&self, ctx: &dyn SlotReservationContext) -> Option<SlotSupplierPermit>;
402
-
403
- /// Marks a slot as actually now being used. This is separate from reserving one because the
404
- /// pollers need to reserve a slot before they have actually obtained work from server. Once
405
- /// that task is obtained (and validated) then the slot can actually be used to work on the
406
- /// task.
407
- ///
408
- /// Users' implementation of this can choose to emit metrics, or otherwise leverage the
409
- /// information provided by the `info` parameter to be better able to make future decisions
410
- /// about whether a slot should be handed out.
411
- fn mark_slot_used(&self, ctx: &dyn SlotMarkUsedContext<SlotKind = Self::SlotKind>);
412
-
413
- /// Frees a slot.
414
- fn release_slot(&self, ctx: &dyn SlotReleaseContext<SlotKind = Self::SlotKind>);
415
-
416
- /// If this implementation knows how many slots are available at any moment, it should return
417
- /// that here.
418
- fn available_slots(&self) -> Option<usize> {
419
- None
420
- }
421
-
422
- /// Returns a human-friendly identifier describing this supplier implementation for
423
- /// diagnostics and telemetry.
424
- fn slot_supplier_kind(&self) -> String {
425
- "Custom".to_string()
426
- }
427
- }
428
-
429
- pub trait SlotReservationContext: Send + Sync {
430
- /// Returns the name of the task queue this worker is polling
431
- fn task_queue(&self) -> &str;
432
-
433
- /// Returns the identity of the worker
434
- fn worker_identity(&self) -> &str;
435
-
436
- /// Returns the deployment version of the worker, if one is set.
437
- fn worker_deployment_version(&self) -> &Option<WorkerDeploymentVersion>;
438
-
439
- /// Returns the number of currently outstanding slot permits, whether used or un-used.
440
- fn num_issued_slots(&self) -> usize;
441
-
442
- /// Returns true iff this is a sticky poll for a workflow task
443
- fn is_sticky(&self) -> bool;
444
-
445
- /// Returns the metrics meter if metrics are enabled
446
- fn get_metrics_meter(&self) -> Option<TemporalMeter> {
447
- None
448
- }
449
- }
450
-
451
- pub trait SlotMarkUsedContext: Send + Sync {
452
- type SlotKind: SlotKind;
453
- /// The slot permit that is being used
454
- fn permit(&self) -> &SlotSupplierPermit;
455
- /// Returns the info of slot that was marked as used
456
- fn info(&self) -> &<Self::SlotKind as SlotKind>::Info;
457
-
458
- /// Returns the metrics meter if metrics are enabled
459
- fn get_metrics_meter(&self) -> Option<TemporalMeter> {
460
- None
461
- }
462
- }
463
-
464
- pub trait SlotReleaseContext: Send + Sync {
465
- type SlotKind: SlotKind;
466
- /// The slot permit that is being used
467
- fn permit(&self) -> &SlotSupplierPermit;
468
- /// Returns the info of slot that was released, if it was used
469
- fn info(&self) -> Option<&<Self::SlotKind as SlotKind>::Info>;
470
-
471
- /// Returns the metrics meter if metrics are enabled
472
- fn get_metrics_meter(&self) -> Option<TemporalMeter> {
473
- None
474
- }
475
- }
476
-
477
- #[derive(Default, Debug)]
478
- pub struct SlotSupplierPermit {
479
- user_data: Option<Box<dyn Any + Send + Sync>>,
480
- }
481
- impl SlotSupplierPermit {
482
- pub fn with_user_data<T: Any + Send + Sync>(user_data: T) -> Self {
483
- Self {
484
- user_data: Some(Box::new(user_data)),
485
- }
486
- }
487
- /// Attempts to downcast the inner data, if any, into the provided type and returns it.
488
- /// Returns none if there is no data or the data is not of the appropriate type.
489
- pub fn user_data<T: Any + Send + Sync>(&self) -> Option<&T> {
490
- self.user_data.as_ref().and_then(|b| b.downcast_ref())
491
- }
492
- /// Attempts to downcast the inner data, if any, into the provided type and returns it mutably.
493
- /// Returns none if there is no data or the data is not of the appropriate type.
494
- pub fn user_data_mut<T: Any + Send + Sync>(&mut self) -> Option<&mut T> {
495
- self.user_data.as_mut().and_then(|b| b.downcast_mut())
496
- }
497
- }
498
-
499
- #[derive(Debug, Copy, Clone, derive_more::Display, Eq, PartialEq)]
500
- pub enum SlotKindType {
501
- Workflow,
502
- Activity,
503
- LocalActivity,
504
- Nexus,
505
- }
506
-
507
- #[derive(Debug, Copy, Clone)]
508
- pub struct WorkflowSlotKind {}
509
- #[derive(Debug, Copy, Clone)]
510
- pub struct ActivitySlotKind {}
511
- #[derive(Debug, Copy, Clone)]
512
- pub struct LocalActivitySlotKind {}
513
- #[derive(Debug, Copy, Clone)]
514
- pub struct NexusSlotKind {}
515
-
516
- pub enum SlotInfo<'a> {
517
- Workflow(&'a WorkflowSlotInfo),
518
- Activity(&'a ActivitySlotInfo),
519
- LocalActivity(&'a LocalActivitySlotInfo),
520
- Nexus(&'a NexusSlotInfo),
521
- }
522
-
523
- pub trait SlotInfoTrait: prost::Message {
524
- fn downcast(&self) -> SlotInfo<'_>;
525
- }
526
- impl SlotInfoTrait for WorkflowSlotInfo {
527
- fn downcast(&self) -> SlotInfo<'_> {
528
- SlotInfo::Workflow(self)
529
- }
530
- }
531
- impl SlotInfoTrait for ActivitySlotInfo {
532
- fn downcast(&self) -> SlotInfo<'_> {
533
- SlotInfo::Activity(self)
534
- }
535
- }
536
- impl SlotInfoTrait for LocalActivitySlotInfo {
537
- fn downcast(&self) -> SlotInfo<'_> {
538
- SlotInfo::LocalActivity(self)
539
- }
540
- }
541
- impl SlotInfoTrait for NexusSlotInfo {
542
- fn downcast(&self) -> SlotInfo<'_> {
543
- SlotInfo::Nexus(self)
544
- }
545
- }
546
-
547
- pub trait SlotKind {
548
- type Info: SlotInfoTrait;
549
-
550
- fn kind() -> SlotKindType;
551
- }
552
- impl SlotKind for WorkflowSlotKind {
553
- type Info = WorkflowSlotInfo;
554
-
555
- fn kind() -> SlotKindType {
556
- SlotKindType::Workflow
557
- }
558
- }
559
- impl SlotKind for ActivitySlotKind {
560
- type Info = ActivitySlotInfo;
561
-
562
- fn kind() -> SlotKindType {
563
- SlotKindType::Activity
564
- }
565
- }
566
- impl SlotKind for LocalActivitySlotKind {
567
- type Info = LocalActivitySlotInfo;
568
-
569
- fn kind() -> SlotKindType {
570
- SlotKindType::LocalActivity
571
- }
572
- }
573
- impl SlotKind for NexusSlotKind {
574
- type Info = NexusSlotInfo;
575
-
576
- fn kind() -> SlotKindType {
577
- SlotKindType::Nexus
578
- }
579
- }
580
-
581
- /// Different strategies for task polling
582
- #[derive(Clone, Copy, Debug, PartialEq)]
583
- pub enum PollerBehavior {
584
- /// Will attempt to poll as long as a slot is available, up to the provided maximum. Cannot
585
- /// be less than two for workflow tasks, or one for other tasks.
586
- SimpleMaximum(usize),
587
- /// Will automatically scale the number of pollers based on feedback from the server. Still
588
- /// requires a slot to be available before beginning polling.
589
- Autoscaling {
590
- /// At least this many poll calls will always be attempted (assuming slots are available).
591
- /// Cannot be zero.
592
- minimum: usize,
593
- /// At most this many poll calls will ever be open at once. Must be >= `minimum`.
594
- maximum: usize,
595
- /// This many polls will be attempted initially before scaling kicks in. Must be between
596
- /// `minimum` and `maximum`.
597
- initial: usize,
598
- },
599
- }
600
-
601
- impl PollerBehavior {
602
- /// Returns true if the behavior is using autoscaling
603
- pub fn is_autoscaling(&self) -> bool {
604
- matches!(self, PollerBehavior::Autoscaling { .. })
605
- }
606
86
 
607
- fn validate(&self) -> Result<(), String> {
608
- match self {
609
- PollerBehavior::SimpleMaximum(x) => {
610
- if *x < 1 {
611
- return Err("SimpleMaximum poller behavior must be at least 1".to_owned());
612
- }
613
- }
614
- PollerBehavior::Autoscaling {
615
- minimum,
616
- maximum,
617
- initial,
618
- } => {
619
- if *minimum < 1 {
620
- return Err("Autoscaling minimum poller behavior must be at least 1".to_owned());
621
- }
622
- if *maximum < *minimum {
623
- return Err(
624
- "Autoscaling maximum must be greater than or equal to minimum".to_owned(),
625
- );
626
- }
627
- if *initial < *minimum || *initial > *maximum {
628
- return Err(
629
- "Autoscaling initial must be between minimum and maximum".to_owned()
630
- );
631
- }
632
- }
87
+ /// Converts the enabled task types into the corresponding [`TaskQueueType`] values.
88
+ pub fn to_task_queue_types(&self) -> Vec<TaskQueueType> {
89
+ let mut types = Vec::new();
90
+ if self.enable_workflows {
91
+ types.push(TaskQueueType::Workflow);
633
92
  }
634
- Ok(())
635
- }
636
- }
637
-
638
- #[derive(Clone, Debug)]
639
- pub enum WorkerVersioningStrategy {
640
- /// Don't enable any versioning
641
- None {
642
- /// Build ID may still be passed as a way to identify the worker, or may be left empty.
643
- build_id: String,
644
- },
645
- /// Maybe use the modern deployment-based versioning, or just pass a deployment version.
646
- WorkerDeploymentBased(WorkerDeploymentOptions),
647
- /// Use the legacy build-id-based whole worker versioning.
648
- LegacyBuildIdBased {
649
- /// A Build ID to use, must be non-empty.
650
- build_id: String,
651
- },
652
- }
653
-
654
- impl Default for WorkerVersioningStrategy {
655
- fn default() -> Self {
656
- WorkerVersioningStrategy::None {
657
- build_id: String::new(),
658
- }
659
- }
660
- }
661
-
662
- impl WorkerVersioningStrategy {
663
- pub fn build_id(&self) -> &str {
664
- match self {
665
- WorkerVersioningStrategy::None { build_id } => build_id,
666
- WorkerVersioningStrategy::WorkerDeploymentBased(opts) => &opts.version.build_id,
667
- WorkerVersioningStrategy::LegacyBuildIdBased { build_id } => build_id,
93
+ if self.enable_remote_activities {
94
+ types.push(TaskQueueType::Activity);
668
95
  }
669
- }
670
-
671
- pub fn uses_build_id_based(&self) -> bool {
672
- matches!(self, WorkerVersioningStrategy::LegacyBuildIdBased { .. })
673
- }
674
-
675
- pub fn default_versioning_behavior(&self) -> Option<VersioningBehavior> {
676
- match self {
677
- WorkerVersioningStrategy::WorkerDeploymentBased(opts) => {
678
- opts.default_versioning_behavior
679
- }
680
- _ => None,
96
+ if self.enable_nexus {
97
+ types.push(TaskQueueType::Nexus);
681
98
  }
99
+ types
682
100
  }
683
101
  }
684
102
 
103
+ /// Configuration for worker deployment versioning.
685
104
  #[derive(Clone, Debug, Eq, PartialEq, Hash)]
686
105
  pub struct WorkerDeploymentOptions {
687
106
  /// The deployment version of this worker.
@@ -694,6 +113,21 @@ pub struct WorkerDeploymentOptions {
694
113
  pub default_versioning_behavior: Option<VersioningBehavior>,
695
114
  }
696
115
 
116
+ impl WorkerDeploymentOptions {
117
+ /// Create deployment options from just a build ID, without opting into worker versioning.
118
+ pub fn from_build_id(build_id: String) -> Self {
119
+ Self {
120
+ version: WorkerDeploymentVersion {
121
+ deployment_name: "".to_owned(),
122
+ build_id,
123
+ },
124
+ use_worker_versioning: false,
125
+ default_versioning_behavior: None,
126
+ }
127
+ }
128
+ }
129
+
130
+ /// Identifies a specific version of a worker deployment.
697
131
  #[derive(Clone, Debug, Eq, PartialEq, Hash)]
698
132
  pub struct WorkerDeploymentVersion {
699
133
  /// Name of the deployment
@@ -703,6 +137,7 @@ pub struct WorkerDeploymentVersion {
703
137
  }
704
138
 
705
139
  impl WorkerDeploymentVersion {
140
+ /// Returns true if both the deployment name and build ID are empty.
706
141
  pub fn is_empty(&self) -> bool {
707
142
  self.deployment_name.is_empty() && self.build_id.is_empty()
708
143
  }
@@ -748,3 +183,33 @@ impl From<temporal::api::deployment::v1::WorkerDeploymentVersion> for WorkerDepl
748
183
  }
749
184
  }
750
185
  }
186
+
187
+ static CACHED_BUILD_ID: OnceLock<String> = OnceLock::new();
188
+
189
+ /// Build ID derived from hashing the on-disk bytes of the current executable.
190
+ /// Deterministic across machines for the same binary. Cached per-process.
191
+ pub fn build_id_from_current_exe() -> &'static str {
192
+ CACHED_BUILD_ID
193
+ .get_or_init(|| compute_crc32_exe_id().unwrap_or_else(|_| "undetermined".to_owned()))
194
+ }
195
+
196
+ fn compute_crc32_exe_id() -> io::Result<String> {
197
+ let exe_path = std::env::current_exe()?;
198
+ let file = File::open(exe_path)?;
199
+ let mut reader = BufReader::new(file);
200
+
201
+ let mut hasher = crc32fast::Hasher::new();
202
+ let mut buf = [0u8; 128 * 1024];
203
+
204
+ loop {
205
+ let n = reader.read(&mut buf)?;
206
+ if n == 0 {
207
+ break;
208
+ }
209
+ hasher.update(&buf[..n]);
210
+ }
211
+
212
+ let crc = hasher.finalize();
213
+
214
+ Ok(format!("{:08x}", crc))
215
+ }