@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,15 @@
1
- use std::time::Duration;
2
- use tokio::sync::mpsc::UnboundedSender;
1
+ use crate::{errors::WorkflowErrorType, telemetry::metrics::TemporalMeter};
2
+ use std::{
3
+ any::Any,
4
+ collections::{HashMap, HashSet},
5
+ sync::Arc,
6
+ time::Duration,
7
+ };
3
8
 
4
- const MAX_OUTSTANDING_WFT_DEFAULT: usize = 100;
5
9
  const MAX_CONCURRENT_WFT_POLLS_DEFAULT: usize = 5;
6
10
 
7
11
  /// Defines per-worker configuration options
8
- #[derive(Debug, Clone, derive_builder::Builder, serde::Serialize, serde::Deserialize)]
12
+ #[derive(Clone, derive_builder::Builder)]
9
13
  #[builder(setter(into), build_fn(validate = "Self::validate"))]
10
14
  #[non_exhaustive]
11
15
  pub struct WorkerConfig {
@@ -29,20 +33,10 @@ pub struct WorkerConfig {
29
33
  /// or failures.
30
34
  #[builder(default = "0")]
31
35
  pub max_cached_workflows: usize,
32
- /// The maximum allowed number of workflow tasks that will ever be given to this worker at one
33
- /// time. Note that one workflow task may require multiple activations - so the WFT counts as
34
- /// "outstanding" until all activations it requires have been completed.
35
- ///
36
- /// Cannot be larger than `max_cached_workflows`.
37
- #[builder(default = "MAX_OUTSTANDING_WFT_DEFAULT")]
38
- pub max_outstanding_workflow_tasks: usize,
39
- /// The maximum number of activity tasks that will ever be given to this worker concurrently
40
- #[builder(default = "100")]
41
- pub max_outstanding_activities: usize,
42
- /// The maximum number of local activity tasks that will ever be given to this worker
43
- /// concurrently
44
- #[builder(default = "100")]
45
- pub max_outstanding_local_activities: usize,
36
+ /// Set a [WorkerTuner] for this worker. Either this or at least one of the `max_outstanding_*`
37
+ /// fields must be set.
38
+ #[builder(setter(into = false, strip_option), default)]
39
+ pub tuner: Option<Arc<dyn WorkerTuner + Send + Sync>>,
46
40
  /// Maximum number of concurrent poll workflow task requests we will perform at a time on this
47
41
  /// worker's task queue. See also [WorkerConfig::nonsticky_to_sticky_poll_ratio]. Must be at
48
42
  /// least 1.
@@ -115,14 +109,6 @@ pub struct WorkerConfig {
115
109
  #[builder(default = "5")]
116
110
  pub fetching_concurrency: usize,
117
111
 
118
- // TODO: Move this out - dependency on tokio should not exist just for this
119
- /// If set, and the `save_wf_inputs` feature is enabled in core, will be sent a serialized
120
- /// instance of every input to workflow state in order. This is for testing purposes, SDK
121
- /// implementations never need to care about it.
122
- #[builder(default)]
123
- #[serde(skip)]
124
- pub wf_state_inputs: Option<UnboundedSender<Vec<u8>>>,
125
-
126
112
  /// If set, core will issue cancels for all outstanding activities after shutdown has been
127
113
  /// initiated and this amount of time has elapsed.
128
114
  #[builder(default)]
@@ -133,6 +119,35 @@ pub struct WorkerConfig {
133
119
  /// timeout.
134
120
  #[builder(default = "Duration::from_secs(5)")]
135
121
  pub local_timeout_buffer_for_activities: Duration,
122
+
123
+ /// Any error types listed here will cause any workflow being processed by this worker to fail,
124
+ /// rather than simply failing the workflow task.
125
+ #[builder(default)]
126
+ pub workflow_failure_errors: HashSet<WorkflowErrorType>,
127
+
128
+ /// Like [WorkerConfig::workflow_failure_errors], but specific to certain workflow types (the
129
+ /// map key).
130
+ #[builder(default)]
131
+ pub workflow_types_to_failure_errors: HashMap<String, HashSet<WorkflowErrorType>>,
132
+
133
+ /// The maximum allowed number of workflow tasks that will ever be given to this worker at one
134
+ /// time. Note that one workflow task may require multiple activations - so the WFT counts as
135
+ /// "outstanding" until all activations it requires have been completed.
136
+ ///
137
+ /// Mutually exclusive with `tuner`
138
+ #[builder(setter(into, strip_option), default)]
139
+ pub max_outstanding_workflow_tasks: Option<usize>,
140
+ /// The maximum number of activity tasks that will ever be given to this worker concurrently
141
+ ///
142
+ /// Mutually exclusive with `tuner`
143
+ #[builder(setter(into, strip_option), default)]
144
+ pub max_outstanding_activities: Option<usize>,
145
+ /// The maximum number of local activity tasks that will ever be given to this worker
146
+ /// concurrently
147
+ ///
148
+ /// Mutually exclusive with `tuner`
149
+ #[builder(setter(into, strip_option), default)]
150
+ pub max_outstanding_local_activities: Option<usize>,
136
151
  }
137
152
 
138
153
  impl WorkerConfig {
@@ -145,9 +160,31 @@ impl WorkerConfig {
145
160
  .saturating_sub(self.max_nonsticky_polls())
146
161
  .max(1)
147
162
  }
163
+ /// Returns true if the configuration specifies we should fail a workflow on a certain error
164
+ /// type rather than failing the workflow task.
165
+ pub fn should_fail_workflow(
166
+ &self,
167
+ workflow_type: &str,
168
+ error_type: &WorkflowErrorType,
169
+ ) -> bool {
170
+ self.workflow_failure_errors.contains(error_type)
171
+ || self
172
+ .workflow_types_to_failure_errors
173
+ .get(workflow_type)
174
+ .map(|s| s.contains(error_type))
175
+ .unwrap_or(false)
176
+ }
148
177
  }
149
178
 
150
179
  impl WorkerConfigBuilder {
180
+ /// Unset all `max_outstanding_*` fields
181
+ pub fn clear_max_outstanding_opts(&mut self) -> &mut Self {
182
+ self.max_outstanding_workflow_tasks = None;
183
+ self.max_outstanding_activities = None;
184
+ self.max_outstanding_local_activities = None;
185
+ self
186
+ }
187
+
151
188
  fn validate(&self) -> Result<(), String> {
152
189
  if self.max_concurrent_wft_polls == Some(0) {
153
190
  return Err("`max_concurrent_wft_polls` must be at least 1".to_owned());
@@ -155,15 +192,7 @@ impl WorkerConfigBuilder {
155
192
  if self.max_concurrent_at_polls == Some(0) {
156
193
  return Err("`max_concurrent_at_polls` must be at least 1".to_owned());
157
194
  }
158
- if self.max_cached_workflows > Some(0)
159
- && self.max_outstanding_workflow_tasks > self.max_cached_workflows
160
- {
161
- return Err(
162
- "Maximum concurrent workflow tasks cannot exceed the maximum number of cached \
163
- workflows"
164
- .to_owned(),
165
- );
166
- }
195
+
167
196
  if let Some(Some(ref x)) = self.max_worker_activities_per_second {
168
197
  if !x.is_normal() || x.is_sign_negative() {
169
198
  return Err(
@@ -171,30 +200,28 @@ impl WorkerConfigBuilder {
171
200
  );
172
201
  }
173
202
  }
174
- if matches!(self.max_concurrent_wft_polls, Some(1))
175
- && self.max_cached_workflows > Some(0)
176
- && self
177
- .max_outstanding_workflow_tasks
178
- .unwrap_or(MAX_OUTSTANDING_WFT_DEFAULT)
179
- <= 1
203
+
204
+ if self.tuner.is_some()
205
+ && (self.max_outstanding_workflow_tasks.is_some()
206
+ || self.max_outstanding_activities.is_some()
207
+ || self.max_outstanding_local_activities.is_some())
180
208
  {
181
- return Err(
182
- "`max_outstanding_workflow_tasks` must be at at least 2 when \
183
- `max_cached_workflows` is nonzero"
184
- .to_owned(),
185
- );
209
+ return Err("max_outstanding_* fields are mutually exclusive with `tuner`".to_owned());
186
210
  }
187
- if self
211
+
212
+ let max_wft_polls = self
188
213
  .max_concurrent_wft_polls
189
- .unwrap_or(MAX_CONCURRENT_WFT_POLLS_DEFAULT)
190
- > self
191
- .max_outstanding_workflow_tasks
192
- .unwrap_or(MAX_OUTSTANDING_WFT_DEFAULT)
193
- {
194
- return Err(
195
- "`max_concurrent_wft_polls` cannot exceed `max_outstanding_workflow_tasks`"
196
- .to_owned(),
197
- );
214
+ .unwrap_or(MAX_CONCURRENT_WFT_POLLS_DEFAULT);
215
+
216
+ // It wouldn't make any sense to have more outstanding polls than workflows we can possibly
217
+ // cache. If we allow this at low values it's possible for sticky pollers to reserve all
218
+ // available slots, crowding out the normal queue and gumming things up.
219
+ if let Some(max_cache) = self.max_cached_workflows {
220
+ if max_cache > 0 && max_wft_polls > max_cache {
221
+ return Err(
222
+ "`max_concurrent_wft_polls` cannot exceed `max_cached_workflows`".to_owned(),
223
+ );
224
+ }
198
225
  }
199
226
 
200
227
  if self.use_worker_versioning.unwrap_or_default()
@@ -212,3 +239,132 @@ impl WorkerConfigBuilder {
212
239
  Ok(())
213
240
  }
214
241
  }
242
+
243
+ /// This trait allows users to customize the performance characteristics of workers dynamically.
244
+ /// For more, see the docstrings of the traits in the return types of its functions.
245
+ pub trait WorkerTuner {
246
+ /// Return a [SlotSupplier] for workflow tasks
247
+ fn workflow_task_slot_supplier(
248
+ &self,
249
+ ) -> Arc<dyn SlotSupplier<SlotKind = WorkflowSlotKind> + Send + Sync>;
250
+
251
+ /// Return a [SlotSupplier] for activity tasks
252
+ fn activity_task_slot_supplier(
253
+ &self,
254
+ ) -> Arc<dyn SlotSupplier<SlotKind = ActivitySlotKind> + Send + Sync>;
255
+
256
+ /// Return a [SlotSupplier] for local activities
257
+ fn local_activity_slot_supplier(
258
+ &self,
259
+ ) -> Arc<dyn SlotSupplier<SlotKind = LocalActivitySlotKind> + Send + Sync>;
260
+
261
+ /// Core will call this at worker initialization time, allowing the implementation to hook up to
262
+ /// metrics if any are configured. If not, it will not be called.
263
+ fn attach_metrics(&self, metrics: TemporalMeter);
264
+ }
265
+
266
+ /// Implementing this trait allows users to customize how many tasks of certain kinds the worker
267
+ /// will perform concurrently.
268
+ ///
269
+ /// Note that, for implementations on workflow tasks ([WorkflowSlotKind]), workers that have the
270
+ /// workflow cache enabled should be willing to hand out _at least_ two slots, to avoid the worker
271
+ /// becoming stuck only polling on the worker's sticky queue.
272
+ #[async_trait::async_trait]
273
+ pub trait SlotSupplier {
274
+ type SlotKind: SlotKind;
275
+ /// Block until a slot is available, then return a permit for the slot.
276
+ async fn reserve_slot(&self, ctx: &dyn SlotReservationContext) -> SlotSupplierPermit;
277
+
278
+ /// Try to immediately reserve a slot, returning None if one is not available
279
+ fn try_reserve_slot(&self, ctx: &dyn SlotReservationContext) -> Option<SlotSupplierPermit>;
280
+
281
+ /// Marks a slot as actually now being used. This is separate from reserving one because the
282
+ /// pollers need to reserve a slot before they have actually obtained work from server. Once
283
+ /// that task is obtained (and validated) then the slot can actually be used to work on the
284
+ /// task.
285
+ ///
286
+ /// Users' implementation of this can choose to emit metrics, or otherwise leverage the
287
+ /// information provided by the `info` parameter to be better able to make future decisions
288
+ /// about whether a slot should be handed out.
289
+ fn mark_slot_used(&self, info: <Self::SlotKind as SlotKind>::Info<'_>);
290
+
291
+ /// Frees a slot.
292
+ fn release_slot(&self);
293
+
294
+ /// If this implementation knows how many slots are available at any moment, it should return
295
+ /// that here.
296
+ fn available_slots(&self) -> Option<usize> {
297
+ None
298
+ }
299
+ }
300
+
301
+ pub trait SlotReservationContext: Send + Sync {
302
+ /// Returns the number of currently outstanding slot permits, whether used or un-used.
303
+ fn num_issued_slots(&self) -> usize;
304
+ }
305
+
306
+ #[derive(Default)]
307
+ pub struct SlotSupplierPermit {
308
+ user_data: Option<Box<dyn Any + Send + Sync>>,
309
+ }
310
+ impl SlotSupplierPermit {
311
+ pub fn with_user_data<T: Any + Send + Sync>(user_data: T) -> Self {
312
+ Self {
313
+ user_data: Some(Box::new(user_data)),
314
+ }
315
+ }
316
+ /// Attempts to downcast the inner data, if any, into the provided type and returns it.
317
+ /// Returns none if there is no data or the data is not of the appropriate type.
318
+ pub fn user_data<T: Any + Send + Sync>(&self) -> Option<&T> {
319
+ self.user_data.as_ref().and_then(|b| b.downcast_ref())
320
+ }
321
+ /// Attempts to downcast the inner data, if any, into the provided type and returns it mutably.
322
+ /// Returns none if there is no data or the data is not of the appropriate type.
323
+ pub fn user_data_mut<T: Any + Send + Sync>(&mut self) -> Option<&mut T> {
324
+ self.user_data.as_mut().and_then(|b| b.downcast_mut())
325
+ }
326
+ }
327
+
328
+ pub struct WorkflowSlotInfo<'a> {
329
+ pub workflow_type: &'a str,
330
+ // etc...
331
+ }
332
+
333
+ pub struct ActivitySlotInfo<'a> {
334
+ pub activity_type: &'a str,
335
+ // etc...
336
+ }
337
+ pub struct LocalActivitySlotInfo<'a> {
338
+ pub activity_type: &'a str,
339
+ // etc...
340
+ }
341
+
342
+ #[derive(Debug)]
343
+ pub struct WorkflowSlotKind {}
344
+ #[derive(Debug)]
345
+ pub struct ActivitySlotKind {}
346
+ #[derive(Debug)]
347
+ pub struct LocalActivitySlotKind {}
348
+ pub trait SlotKind {
349
+ type Info<'a>;
350
+ fn kind_name() -> &'static str;
351
+ }
352
+ impl SlotKind for WorkflowSlotKind {
353
+ type Info<'a> = WorkflowSlotInfo<'a>;
354
+
355
+ fn kind_name() -> &'static str {
356
+ "workflow"
357
+ }
358
+ }
359
+ impl SlotKind for ActivitySlotKind {
360
+ type Info<'a> = ActivitySlotInfo<'a>;
361
+ fn kind_name() -> &'static str {
362
+ "activity"
363
+ }
364
+ }
365
+ impl SlotKind for LocalActivitySlotKind {
366
+ type Info<'a> = LocalActivitySlotInfo<'a>;
367
+ fn kind_name() -> &'static str {
368
+ "local_activity"
369
+ }
370
+ }
@@ -16,3 +16,6 @@ rustfsm_trait = { version = "0.1", path = "rustfsm_trait" }
16
16
 
17
17
  [package.metadata.workspaces]
18
18
  independent = true
19
+
20
+ [lints]
21
+ workspace = true
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `One: From<Two>` is not satisfied
2
2
  --> tests/trybuild/no_handle_conversions_require_into_fail.rs:11:5
3
3
  |
4
4
  11 | Two --(B)--> One;
5
- | ^^^ the trait `From<Two>` is not implemented for `One`
5
+ | ^^^ the trait `From<Two>` is not implemented for `One`, which is required by `Two: Into<One>`
6
6
  |
7
7
  = note: required for `Two` to implement `Into<One>`
8
8
  note: required by a bound in `TransitionResult::<Sm, Ds>::from`
@@ -10,30 +10,25 @@ repository = "https://github.com/temporalio/sdk-core"
10
10
  keywords = ["temporal", "workflow"]
11
11
  categories = ["development-tools"]
12
12
 
13
- # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14
-
15
13
  [dependencies]
16
14
  async-trait = "0.1"
17
15
  thiserror = "1.0"
18
16
  anyhow = "1.0"
19
- base64 = "0.21"
20
17
  crossbeam-channel = "0.5"
21
18
  derive_more = { workspace = true }
22
19
  futures = "0.3"
23
- once_cell = "1.10"
24
20
  parking_lot = { version = "0.12", features = ["send_guard"] }
25
- prost-types = { version = "0.4", package = "prost-wkt-types" }
26
- sha2 = "0.10"
21
+ prost-types = { version = "0.5", package = "prost-wkt-types" }
27
22
  serde = "1.0"
28
23
  tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
29
24
  tokio-util = { version = "0.7" }
30
25
  tokio-stream = "0.1"
31
- tonic = { workspace = true }
32
26
  tracing = "0.1"
33
27
 
34
28
  [dependencies.temporal-sdk-core]
35
29
  path = "../core"
36
30
  version = "0.1"
31
+ default-features = false
37
32
 
38
33
  [dependencies.temporal-sdk-core-protos]
39
34
  path = "../sdk-core-protos"
@@ -46,3 +41,6 @@ version = "0.1"
46
41
  [dependencies.temporal-client]
47
42
  path = "../client"
48
43
  version = "0.1"
44
+
45
+ [lints]
46
+ workspace = true
@@ -6,20 +6,20 @@ use std::{
6
6
 
7
7
  /// A Wrapper Type for workflow and activity app data
8
8
  #[derive(Default)]
9
- pub struct AppData {
9
+ pub(crate) struct AppData {
10
10
  map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
11
11
  }
12
12
 
13
13
  impl AppData {
14
14
  /// Insert an item, overwritting duplicates
15
- pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
15
+ pub(crate) fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
16
16
  self.map
17
17
  .insert(TypeId::of::<T>(), Box::new(val))
18
18
  .and_then(downcast_owned)
19
19
  }
20
20
 
21
21
  /// Get a reference to a type in the map
22
- pub fn get<T: 'static>(&self) -> Option<&T> {
22
+ pub(crate) fn get<T: 'static>(&self) -> Option<&T> {
23
23
  self.map
24
24
  .get(&TypeId::of::<T>())
25
25
  .and_then(|boxed| boxed.downcast_ref())
@@ -17,7 +17,7 @@
17
17
  //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
18
18
  //! let server_options = sdk_client_options(Url::from_str("http://localhost:7233")?).build()?;
19
19
  //!
20
- //! let client = server_options.connect("default", None, None).await?;
20
+ //! let client = server_options.connect("default", None).await?;
21
21
  //!
22
22
  //! let telemetry_options = TelemetryOptionsBuilder::default().build()?;
23
23
  //! let runtime = CoreRuntime::new_assume_tokio(telemetry_options)?;
@@ -48,7 +48,6 @@ extern crate tracing;
48
48
  mod activity_context;
49
49
  mod app_data;
50
50
  pub mod interceptors;
51
- mod payload_converter;
52
51
  mod workflow_context;
53
52
  mod workflow_future;
54
53
 
@@ -521,7 +520,10 @@ impl ActivityHalf {
521
520
  });
522
521
  }
523
522
  Some(activity_task::Variant::Cancel(_)) => {
524
- if let Some(ct) = self.task_tokens_to_cancels.get(&activity.task_token.into()) {
523
+ if let Some(ct) = self
524
+ .task_tokens_to_cancels
525
+ .get(activity.task_token.as_slice())
526
+ {
525
527
  ct.cancel();
526
528
  }
527
529
  }
@@ -17,7 +17,7 @@ use temporal_sdk_core_protos::{
17
17
 
18
18
  // TODO: Before release, probably best to avoid using proto types entirely here. They're awkward.
19
19
 
20
- pub trait IntoWorkflowCommand {
20
+ pub(crate) trait IntoWorkflowCommand {
21
21
  type WFCommandType;
22
22
 
23
23
  /// Produces a workflow command from some options
@@ -98,11 +98,11 @@ impl WfCtxProtectedDat {
98
98
  #[derive(Clone, Debug, Default)]
99
99
  pub(crate) struct WfContextSharedData {
100
100
  /// Maps change ids -> resolved status
101
- pub changes: HashMap<String, bool>,
102
- pub is_replaying: bool,
103
- pub wf_time: Option<SystemTime>,
104
- pub history_length: u32,
105
- pub current_build_id: Option<String>,
101
+ pub(crate) changes: HashMap<String, bool>,
102
+ pub(crate) is_replaying: bool,
103
+ pub(crate) wf_time: Option<SystemTime>,
104
+ pub(crate) history_length: u32,
105
+ pub(crate) current_build_id: Option<String>,
106
106
  }
107
107
 
108
108
  // TODO: Dataconverter type interface to replace Payloads here. Possibly just use serde
@@ -204,7 +204,7 @@ impl WfContext {
204
204
  mut opts: ActivityOptions,
205
205
  ) -> impl CancellableFuture<ActivityResolution> {
206
206
  if opts.task_queue.is_empty() {
207
- opts.task_queue = self.task_queue.clone()
207
+ opts.task_queue.clone_from(&self.task_queue);
208
208
  }
209
209
  let seq = self.seq_nums.write().next_activity_seq();
210
210
  let (cmd, unblocker) = CancellableWFCommandFut::new(CancellableID::Activity(seq));
@@ -573,7 +573,8 @@ impl<'a> Future for LATimerBackoffFut<'a> {
573
573
  if let TimerResult::Fired = tr {
574
574
  let mut opts = self.la_opts.clone();
575
575
  opts.attempt = Some(self.next_attempt);
576
- opts.original_schedule_time = self.next_sched_time.clone();
576
+ opts.original_schedule_time
577
+ .clone_from(&self.next_sched_time);
577
578
  self.current_fut = Box::pin(self.ctx.local_activity_no_timer_retry(opts));
578
579
  Poll::Pending
579
580
  } else {
@@ -608,7 +609,7 @@ impl<'a> Future for LATimerBackoffFut<'a> {
608
609
  );
609
610
  self.timer_fut = Some(Box::pin(timer_f));
610
611
  self.next_attempt = b.attempt;
611
- self.next_sched_time = b.original_schedule_time.clone();
612
+ self.next_sched_time.clone_from(&b.original_schedule_time);
612
613
  return Poll::Pending;
613
614
  }
614
615
  }
@@ -631,7 +632,7 @@ pub struct ChildWorkflow {
631
632
  opts: ChildWorkflowOptions,
632
633
  }
633
634
 
634
- pub struct ChildWfCommon {
635
+ pub(crate) struct ChildWfCommon {
635
636
  workflow_id: String,
636
637
  result_future: CancellableWFCommandFut<ChildWorkflowResult, ()>,
637
638
  }
@@ -93,7 +93,7 @@ enum SigChanOrBuffer {
93
93
  Buffer(Vec<SignalData>),
94
94
  }
95
95
 
96
- pub struct WorkflowFuture {
96
+ pub(crate) struct WorkflowFuture {
97
97
  /// Future produced by calling the workflow function
98
98
  inner: BoxFuture<'static, WorkflowResult<Payload>>,
99
99
  /// Commands produced inside user's wf code
@@ -12,15 +12,14 @@ categories = ["development-tools"]
12
12
 
13
13
  [features]
14
14
  history_builders = ["uuid", "rand"]
15
- serde_serialize = []
16
15
 
17
16
  [dependencies]
18
17
  anyhow = "1.0"
19
- base64 = "0.21"
18
+ base64 = "0.22"
20
19
  derive_more = { workspace = true }
21
- prost = "0.11"
22
- prost-wkt = "0.4"
23
- prost-wkt-types = "0.4"
20
+ prost = { workspace = true }
21
+ prost-wkt = "0.5"
22
+ prost-wkt-types = "0.5"
24
23
  rand = { version = "0.8", optional = true }
25
24
  serde = { version = "1.0", features = ["derive"] }
26
25
  serde_json = "1.0"
@@ -30,4 +29,7 @@ uuid = { version = "1.1", features = ["v4"], optional = true }
30
29
 
31
30
  [build-dependencies]
32
31
  tonic-build = { workspace = true }
33
- prost-wkt-build = "0.4"
32
+ prost-wkt-build = "0.5"
33
+
34
+ [lints]
35
+ workspace = true
@@ -112,7 +112,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
112
112
  ".google.protobuf.Value",
113
113
  "::prost_wkt_types::Value"
114
114
  )
115
- .file_descriptor_set_path(#[allow(clippy::needless_borrow)] &descriptor_file)
115
+ .file_descriptor_set_path(descriptor_file)
116
116
  .compile(
117
117
  &[
118
118
  "./protos/local/temporal/sdk/core/core_interface.proto",
@@ -129,14 +129,5 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
129
129
  ],
130
130
  )?;
131
131
 
132
- #[cfg(feature = "serde_serialize")]
133
- {
134
- use prost_wkt_build::{FileDescriptorSet, Message};
135
-
136
- let descriptor_bytes = std::fs::read(descriptor_file)?;
137
- let descriptor = FileDescriptorSet::decode(&descriptor_bytes[..])?;
138
- prost_wkt_build::add_serde(out, descriptor);
139
- }
140
-
141
132
  Ok(())
142
133
  }
@@ -9,3 +9,6 @@
9
9
  <!-- Are there any breaking changes on binary or code level? -->
10
10
  **Breaking changes**
11
11
 
12
+
13
+ <!-- If this breaks the Server, please provide the Server PR to merge right after this PR was merged. -->
14
+ **Server PR**
@@ -0,0 +1,26 @@
1
+ name: ci
2
+ on:
3
+ pull_request:
4
+ permissions:
5
+ contents: read
6
+ jobs:
7
+ ci:
8
+ name: ci
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-go@v4
13
+ with:
14
+ go-version: '^1.21'
15
+ - uses: arduino/setup-protoc@v2
16
+ - name: 'Setup jq'
17
+ uses: dcarbone/install-jq-action@v2
18
+ - run: make ci-build
19
+ - name: Fail if the repo is dirty
20
+ run: |
21
+ if [[ -n $(git status --porcelain) ]]; then
22
+ echo "Detected uncommitted changes."
23
+ git status
24
+ git diff
25
+ exit 1
26
+ fi