@temporalio/core-bridge 1.10.3 → 1.11.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 (126) hide show
  1. package/Cargo.lock +563 -676
  2. package/Cargo.toml +3 -3
  3. package/lib/index.d.ts +16 -5
  4. package/lib/index.js.map +1 -1
  5. package/lib/worker-tuner.d.ts +57 -0
  6. package/lib/worker-tuner.js +3 -0
  7. package/lib/worker-tuner.js.map +1 -0
  8. package/package.json +3 -3
  9. package/releases/aarch64-apple-darwin/index.node +0 -0
  10. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  11. package/releases/x86_64-apple-darwin/index.node +0 -0
  12. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  13. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  14. package/sdk-core/.github/workflows/heavy.yml +6 -11
  15. package/sdk-core/.github/workflows/per-pr.yml +23 -41
  16. package/sdk-core/Cargo.toml +5 -5
  17. package/sdk-core/README.md +2 -0
  18. package/sdk-core/client/Cargo.toml +4 -2
  19. package/sdk-core/client/src/lib.rs +60 -17
  20. package/sdk-core/client/src/metrics.rs +1 -1
  21. package/sdk-core/client/src/proxy.rs +17 -12
  22. package/sdk-core/client/src/raw.rs +218 -69
  23. package/sdk-core/client/src/retry.rs +19 -9
  24. package/sdk-core/core/Cargo.toml +12 -12
  25. package/sdk-core/core/src/abstractions.rs +3 -3
  26. package/sdk-core/core/src/core_tests/activity_tasks.rs +2 -1
  27. package/sdk-core/core/src/core_tests/determinism.rs +1 -1
  28. package/sdk-core/core/src/core_tests/local_activities.rs +73 -10
  29. package/sdk-core/core/src/core_tests/queries.rs +2 -1
  30. package/sdk-core/core/src/core_tests/updates.rs +162 -4
  31. package/sdk-core/core/src/core_tests/workers.rs +38 -2
  32. package/sdk-core/core/src/core_tests/workflow_tasks.rs +158 -27
  33. package/sdk-core/core/src/internal_flags.rs +17 -7
  34. package/sdk-core/core/src/lib.rs +9 -3
  35. package/sdk-core/core/src/pollers/poll_buffer.rs +1 -10
  36. package/sdk-core/core/src/protosext/mod.rs +0 -1
  37. package/sdk-core/core/src/protosext/protocol_messages.rs +105 -16
  38. package/sdk-core/core/src/retry_logic.rs +22 -2
  39. package/sdk-core/core/src/telemetry/otel.rs +44 -12
  40. package/sdk-core/core/src/test_help/mod.rs +65 -12
  41. package/sdk-core/core/src/worker/activities/local_activities.rs +1 -4
  42. package/sdk-core/core/src/worker/activities.rs +3 -4
  43. package/sdk-core/core/src/worker/client/mocks.rs +7 -6
  44. package/sdk-core/core/src/worker/client.rs +11 -2
  45. package/sdk-core/core/src/worker/mod.rs +49 -24
  46. package/sdk-core/core/src/worker/tuner/resource_based.rs +48 -48
  47. package/sdk-core/core/src/worker/tuner.rs +124 -4
  48. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +1 -1
  49. package/sdk-core/core/src/worker/workflow/history_update.rs +11 -2
  50. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +18 -3
  51. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -0
  52. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -0
  53. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -0
  54. package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -0
  55. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -0
  56. package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -0
  57. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +4 -4
  58. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +1 -0
  59. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -0
  60. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -0
  61. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -1
  62. package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +38 -28
  63. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -2
  64. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +95 -71
  65. package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -1
  66. package/sdk-core/core/src/worker/workflow/managed_run.rs +214 -14
  67. package/sdk-core/core/src/worker/workflow/mod.rs +49 -36
  68. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -2
  69. package/sdk-core/core-api/src/errors.rs +13 -7
  70. package/sdk-core/core-api/src/lib.rs +9 -1
  71. package/sdk-core/sdk/Cargo.toml +1 -1
  72. package/sdk-core/sdk/src/activity_context.rs +3 -4
  73. package/sdk-core/sdk/src/lib.rs +96 -49
  74. package/sdk-core/sdk/src/workflow_context/options.rs +8 -4
  75. package/sdk-core/sdk/src/workflow_context.rs +53 -49
  76. package/sdk-core/sdk/src/workflow_future.rs +10 -4
  77. package/sdk-core/sdk-core-protos/Cargo.toml +4 -3
  78. package/sdk-core/sdk-core-protos/build.rs +2 -0
  79. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/.github/workflows/build.yaml +18 -0
  80. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/LICENSE +21 -0
  81. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/Makefile +59 -0
  82. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +25 -0
  83. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -0
  84. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.gen.yaml +14 -0
  85. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.lock +8 -0
  86. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +9 -0
  87. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +520 -0
  88. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +263 -0
  89. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +173 -0
  90. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +164 -0
  91. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +36 -0
  92. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +22 -0
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +50 -8
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/.gitmodules +3 -0
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +132 -54
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +177 -81
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +13 -0
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  99. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +8 -3
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +10 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +3 -3
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +6 -6
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +96 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +49 -0
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +6 -7
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +55 -24
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +7 -0
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +21 -4
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +64 -45
  110. package/sdk-core/sdk-core-protos/src/history_builder.rs +8 -1
  111. package/sdk-core/sdk-core-protos/src/lib.rs +40 -10
  112. package/sdk-core/test-utils/src/canned_histories.rs +1 -1
  113. package/sdk-core/tests/fuzzy_workflow.rs +4 -2
  114. package/sdk-core/tests/heavy_tests.rs +3 -3
  115. package/sdk-core/tests/integ_tests/activity_functions.rs +2 -2
  116. package/sdk-core/tests/integ_tests/client_tests.rs +234 -6
  117. package/sdk-core/tests/integ_tests/update_tests.rs +180 -47
  118. package/sdk-core/tests/integ_tests/worker_tests.rs +32 -0
  119. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +47 -3
  120. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +10 -10
  121. package/sdk-core/tests/main.rs +1 -0
  122. package/src/conversions.rs +84 -11
  123. package/src/runtime.rs +5 -17
  124. package/src/worker.rs +27 -6
  125. package/ts/index.ts +24 -5
  126. package/ts/worker-tuner.ts +71 -0
@@ -25,17 +25,36 @@ use tokio::{sync::watch, task::JoinHandle};
25
25
  /// threshold for each, and slots are handed out if the output of both PID controllers is above some
26
26
  /// defined threshold. See [ResourceBasedSlotsOptions] for the default PID controller settings.
27
27
  pub struct ResourceBasedTuner<MI> {
28
- slots: Arc<ResourceBasedSlots<MI>>,
28
+ slots: Arc<ResourceController<MI>>,
29
29
  wf_opts: Option<ResourceSlotOptions>,
30
30
  act_opts: Option<ResourceSlotOptions>,
31
31
  la_opts: Option<ResourceSlotOptions>,
32
32
  }
33
33
 
34
+ impl ResourceBasedTuner<RealSysInfo> {
35
+ /// Create an instance attempting to target the provided memory and cpu thresholds as values
36
+ /// between 0 and 1.
37
+ pub fn new(target_mem_usage: f64, target_cpu_usage: f64) -> Self {
38
+ let opts = ResourceBasedSlotsOptionsBuilder::default()
39
+ .target_mem_usage(target_mem_usage)
40
+ .target_cpu_usage(target_cpu_usage)
41
+ .build()
42
+ .expect("default resource based slot options can't fail to build");
43
+ let controller = ResourceController::new_with_sysinfo(opts, RealSysInfo::new());
44
+ Self::new_from_controller(controller)
45
+ }
46
+
47
+ /// Create an instance using the fully configurable set of PID controller options
48
+ pub fn new_from_options(options: ResourceBasedSlotsOptions) -> Self {
49
+ let controller = ResourceController::new_with_sysinfo(options, RealSysInfo::new());
50
+ Self::new_from_controller(controller)
51
+ }
52
+ }
53
+
34
54
  impl<MI> ResourceBasedTuner<MI> {
35
- /// Build a new tuner from a [ResourceBasedSlots] instance
36
- pub fn new(resourcer: ResourceBasedSlots<MI>) -> Self {
55
+ fn new_from_controller(controller: ResourceController<MI>) -> Self {
37
56
  Self {
38
- slots: Arc::new(resourcer),
57
+ slots: Arc::new(controller),
39
58
  wf_opts: None,
40
59
  act_opts: None,
41
60
  la_opts: None,
@@ -84,23 +103,22 @@ pub struct ResourceSlotOptions {
84
103
  ramp_throttle: Duration,
85
104
  }
86
105
 
87
- /// Implements [SlotSupplier] and attempts to maintain certain levels of resource usage when
88
- /// under load.
89
- ///
90
- /// It does so by using two PID controllers, one for memory and one for CPU, which are fed the
91
- /// current usage levels of their respective resource as measurements. The user specifies a target
92
- /// threshold for each, and slots are handed out if the output of both PID controllers is above some
93
- /// defined threshold. See [ResourceBasedSlotsOptions] for the default PID controller settings.
94
- pub struct ResourceBasedSlots<MI> {
106
+ struct ResourceController<MI> {
95
107
  options: ResourceBasedSlotsOptions,
96
108
  sys_info_supplier: MI,
97
109
  metrics: OnceLock<JoinHandle<()>>,
98
110
  pids: Mutex<PidControllers>,
99
111
  last_metric_vals: Arc<AtomicCell<LastMetricVals>>,
100
112
  }
101
- /// Wraps [ResourceBasedSlots] for a specific slot type
102
- pub struct ResourceBasedSlotsForType<MI, SK> {
103
- inner: Arc<ResourceBasedSlots<MI>>,
113
+ /// Implements [SlotSupplier] and attempts to maintain certain levels of resource usage when under
114
+ /// load.
115
+ ///
116
+ /// It does so by using two PID controllers, one for memory and one for CPU, which are fed the
117
+ /// current usage levels of their respective resource as measurements. The user specifies a target
118
+ /// threshold for each, and slots are handed out if the output of both PID controllers is above some
119
+ /// defined threshold. See [ResourceBasedSlotsOptions] for the default PID controller settings.
120
+ pub(crate) struct ResourceBasedSlotsForType<MI, SK> {
121
+ inner: Arc<ResourceController<MI>>,
104
122
 
105
123
  opts: ResourceSlotOptions,
106
124
 
@@ -108,28 +126,35 @@ pub struct ResourceBasedSlotsForType<MI, SK> {
108
126
  last_slot_issued_rx: watch::Receiver<Instant>,
109
127
  _slot_kind: PhantomData<SK>,
110
128
  }
129
+ /// Allows for the full customization of the PID options for a resource based tuner
111
130
  #[derive(Clone, Debug, derive_builder::Builder)]
112
131
  #[non_exhaustive]
113
132
  pub struct ResourceBasedSlotsOptions {
114
133
  /// A value in the range [0.0, 1.0] representing the target memory usage.
115
- target_mem_usage: f64,
134
+ pub target_mem_usage: f64,
116
135
  /// A value in the range [0.0, 1.0] representing the target CPU usage.
117
- target_cpu_usage: f64,
136
+ pub target_cpu_usage: f64,
118
137
 
138
+ /// See [pid::Pid::p]
119
139
  #[builder(default = "5.0")]
120
140
  pub mem_p_gain: f64,
141
+ /// See [pid::Pid::i]
121
142
  #[builder(default = "0.0")]
122
143
  pub mem_i_gain: f64,
144
+ /// See [pid::Pid::d]
123
145
  #[builder(default = "1.0")]
124
146
  pub mem_d_gain: f64,
125
147
  /// If the mem PID controller outputs a value higher than this, we say the mem half of things
126
148
  /// will allow a slot
127
149
  #[builder(default = "0.25")]
128
150
  pub mem_output_threshold: f64,
151
+ /// See [pid::Pid::d]
129
152
  #[builder(default = "5.0")]
130
153
  pub cpu_p_gain: f64,
154
+ /// See [pid::Pid::i]
131
155
  #[builder(default = "0.0")]
132
156
  pub cpu_i_gain: f64,
157
+ /// See [pid::Pid::d]
133
158
  #[builder(default = "1.0")]
134
159
  pub cpu_d_gain: f64,
135
160
  /// If the CPU PID controller outputs a value higher than this, we say the CPU half of things
@@ -156,24 +181,6 @@ struct LastMetricVals {
156
181
  cpu_used_percent: f64,
157
182
  }
158
183
 
159
- impl ResourceBasedSlots<RealSysInfo> {
160
- /// Create an instance attempting to target the provided memory and cpu thresholds as values
161
- /// between 0 and 1.
162
- pub fn new(target_mem_usage: f64, target_cpu_usage: f64) -> Self {
163
- let opts = ResourceBasedSlotsOptionsBuilder::default()
164
- .target_mem_usage(target_mem_usage)
165
- .target_cpu_usage(target_cpu_usage)
166
- .build()
167
- .expect("default resource based slot options can't fail to build");
168
- Self::new_with_sysinfo(opts, RealSysInfo::new())
169
- }
170
-
171
- /// Create an instance using the fully configurable set of PID controller options
172
- pub fn new_from_options(options: ResourceBasedSlotsOptions) -> Self {
173
- Self::new_with_sysinfo(options, RealSysInfo::new())
174
- }
175
- }
176
-
177
184
  impl PidControllers {
178
185
  fn new(options: &ResourceBasedSlotsOptions) -> Self {
179
186
  let mut mem = pid::Pid::new(options.target_mem_usage, 100.0);
@@ -272,19 +279,12 @@ where
272
279
  fn release_slot(&self) {}
273
280
  }
274
281
 
275
- impl<MI, SK> ResourceBasedSlotsForType<MI, SK>
276
- where
277
- MI: Send + Sync + SystemResourceInfo,
278
- SK: Send + SlotKind + Sync,
279
- {
280
- }
281
-
282
282
  impl<MI, SK> ResourceBasedSlotsForType<MI, SK>
283
283
  where
284
284
  MI: SystemResourceInfo + Send + Sync,
285
285
  SK: SlotKind + Send + Sync,
286
286
  {
287
- fn new(inner: Arc<ResourceBasedSlots<MI>>, opts: ResourceSlotOptions) -> Self {
287
+ fn new(inner: Arc<ResourceController<MI>>, opts: ResourceSlotOptions) -> Self {
288
288
  let (tx, rx) = watch::channel(Instant::now());
289
289
  Self {
290
290
  opts,
@@ -334,7 +334,7 @@ impl<MI: SystemResourceInfo + Sync + Send + 'static> WorkerTuner for ResourceBas
334
334
  }
335
335
  }
336
336
 
337
- impl<MI: SystemResourceInfo + Sync + Send> ResourceBasedSlots<MI> {
337
+ impl<MI: SystemResourceInfo + Sync + Send> ResourceController<MI> {
338
338
  /// Create a [ResourceBasedSlotsForType] for this instance which is willing to hand out
339
339
  /// `minimum` slots with no checks at all and `max` slots ever. Otherwise the underlying
340
340
  /// mem/cpu targets will attempt to be matched while under load.
@@ -344,7 +344,7 @@ impl<MI: SystemResourceInfo + Sync + Send> ResourceBasedSlots<MI> {
344
344
  /// where activities might use a lot of resources, because otherwise the implementation may
345
345
  /// hand out many slots quickly before resource usage has a chance to be reflected, possibly
346
346
  /// resulting in OOM (for example).
347
- pub fn as_kind<SK: SlotKind + Send + Sync>(
347
+ pub(crate) fn as_kind<SK: SlotKind + Send + Sync>(
348
348
  self: &Arc<Self>,
349
349
  opts: ResourceSlotOptions,
350
350
  ) -> Arc<ResourceBasedSlotsForType<MI, SK>> {
@@ -506,7 +506,7 @@ mod tests {
506
506
  #[test]
507
507
  fn mem_workflow_sync() {
508
508
  let (fmis, used) = FakeMIS::new();
509
- let rbs = Arc::new(ResourceBasedSlots::new_with_sysinfo(test_options(), fmis))
509
+ let rbs = Arc::new(ResourceController::new_with_sysinfo(test_options(), fmis))
510
510
  .as_kind::<WorkflowSlotKind>(ResourceSlotOptions {
511
511
  min_slots: 0,
512
512
  max_slots: 100,
@@ -522,7 +522,7 @@ mod tests {
522
522
  async fn mem_workflow_async() {
523
523
  let (fmis, used) = FakeMIS::new();
524
524
  used.store(90_000, Ordering::Release);
525
- let rbs = Arc::new(ResourceBasedSlots::new_with_sysinfo(test_options(), fmis))
525
+ let rbs = Arc::new(ResourceController::new_with_sysinfo(test_options(), fmis))
526
526
  .as_kind::<WorkflowSlotKind>(ResourceSlotOptions {
527
527
  min_slots: 0,
528
528
  max_slots: 100,
@@ -546,7 +546,7 @@ mod tests {
546
546
  #[test]
547
547
  fn minimum_respected() {
548
548
  let (fmis, used) = FakeMIS::new();
549
- let rbs = Arc::new(ResourceBasedSlots::new_with_sysinfo(test_options(), fmis))
549
+ let rbs = Arc::new(ResourceController::new_with_sysinfo(test_options(), fmis))
550
550
  .as_kind::<WorkflowSlotKind>(ResourceSlotOptions {
551
551
  min_slots: 2,
552
552
  max_slots: 100,
@@ -3,7 +3,8 @@ mod resource_based;
3
3
 
4
4
  pub use fixed_size::FixedSizeSlotSupplier;
5
5
  pub use resource_based::{
6
- RealSysInfo, ResourceBasedSlots, ResourceBasedTuner, ResourceSlotOptions,
6
+ RealSysInfo, ResourceBasedSlotsOptions, ResourceBasedSlotsOptionsBuilder, ResourceBasedTuner,
7
+ ResourceSlotOptions,
7
8
  };
8
9
 
9
10
  use std::sync::{Arc, OnceLock};
@@ -23,6 +24,125 @@ pub struct TunerHolder {
23
24
  metrics: OnceLock<TemporalMeter>,
24
25
  }
25
26
 
27
+ /// Can be used to construct a [TunerHolder] without needing to manually construct each
28
+ /// [SlotSupplier]. Useful for lang bridges to allow more easily passing through user options.
29
+ #[derive(Clone, Debug, derive_builder::Builder)]
30
+ #[builder(build_fn(validate = "Self::validate"))]
31
+ #[non_exhaustive]
32
+ pub struct TunerHolderOptions {
33
+ /// Options for workflow slots
34
+ #[builder(default, setter(strip_option))]
35
+ pub workflow_slot_options: Option<SlotSupplierOptions>,
36
+ /// Options for activity slots
37
+ #[builder(default, setter(strip_option))]
38
+ pub activity_slot_options: Option<SlotSupplierOptions>,
39
+ /// Options for local activity slots
40
+ #[builder(default, setter(strip_option))]
41
+ pub local_activity_slot_options: Option<SlotSupplierOptions>,
42
+ /// Options that will apply to all resource based slot suppliers. Must be set if any slot
43
+ /// options are [SlotSupplierOptions::ResourceBased]
44
+ #[builder(default, setter(strip_option))]
45
+ pub resource_based_options: Option<ResourceBasedSlotsOptions>,
46
+ }
47
+
48
+ impl TunerHolderOptions {
49
+ /// Create a [TunerHolder] from these options
50
+ pub fn build_tuner_holder(self) -> Result<TunerHolder, anyhow::Error> {
51
+ let mut builder = TunerBuilder::default();
52
+ // safety note: unwraps here are OK since the builder validator guarantees options for
53
+ // a resource based tuner are present if any supplier is resource based
54
+ let mut rb_tuner = self
55
+ .resource_based_options
56
+ .map(ResourceBasedTuner::new_from_options);
57
+ match self.workflow_slot_options {
58
+ Some(SlotSupplierOptions::FixedSize { slots }) => {
59
+ builder.workflow_slot_supplier(Arc::new(FixedSizeSlotSupplier::new(slots)));
60
+ }
61
+ Some(SlotSupplierOptions::ResourceBased(rso)) => {
62
+ builder.workflow_slot_supplier(
63
+ rb_tuner
64
+ .as_mut()
65
+ .unwrap()
66
+ .with_workflow_slots_options(rso)
67
+ .workflow_task_slot_supplier(),
68
+ );
69
+ }
70
+ None => {}
71
+ }
72
+ match self.activity_slot_options {
73
+ Some(SlotSupplierOptions::FixedSize { slots }) => {
74
+ builder.activity_slot_supplier(Arc::new(FixedSizeSlotSupplier::new(slots)));
75
+ }
76
+ Some(SlotSupplierOptions::ResourceBased(rso)) => {
77
+ builder.activity_slot_supplier(
78
+ rb_tuner
79
+ .as_mut()
80
+ .unwrap()
81
+ .with_activity_slots_options(rso)
82
+ .activity_task_slot_supplier(),
83
+ );
84
+ }
85
+ None => {}
86
+ }
87
+ match self.local_activity_slot_options {
88
+ Some(SlotSupplierOptions::FixedSize { slots }) => {
89
+ builder.local_activity_slot_supplier(Arc::new(FixedSizeSlotSupplier::new(slots)));
90
+ }
91
+ Some(SlotSupplierOptions::ResourceBased(rso)) => {
92
+ builder.local_activity_slot_supplier(
93
+ rb_tuner
94
+ .as_mut()
95
+ .unwrap()
96
+ .with_local_activity_slots_options(rso)
97
+ .local_activity_slot_supplier(),
98
+ );
99
+ }
100
+ None => {}
101
+ }
102
+ Ok(builder.build())
103
+ }
104
+ }
105
+
106
+ /// Options for known kinds of slot suppliers
107
+ #[derive(Clone, Debug)]
108
+ pub enum SlotSupplierOptions {
109
+ /// Options for a [FixedSizeSlotSupplier]
110
+ FixedSize {
111
+ /// The number of slots the fixed supplier will have
112
+ slots: usize,
113
+ },
114
+ /// Options for a [ResourceBasedSlots]
115
+ ResourceBased(ResourceSlotOptions),
116
+ }
117
+
118
+ impl TunerHolderOptionsBuilder {
119
+ /// Create a [TunerHolder] from this builder
120
+ pub fn build_tuner_holder(self) -> Result<TunerHolder, anyhow::Error> {
121
+ let s = self.build()?;
122
+ s.build_tuner_holder()
123
+ }
124
+
125
+ fn validate(&self) -> Result<(), String> {
126
+ let any_is_resource_based = matches!(
127
+ self.workflow_slot_options,
128
+ Some(Some(SlotSupplierOptions::ResourceBased(_)))
129
+ ) || matches!(
130
+ self.activity_slot_options,
131
+ Some(Some(SlotSupplierOptions::ResourceBased(_)))
132
+ ) || matches!(
133
+ self.local_activity_slot_options,
134
+ Some(Some(SlotSupplierOptions::ResourceBased(_)))
135
+ );
136
+ if any_is_resource_based && matches!(self.resource_based_options, None | Some(None)) {
137
+ return Err(
138
+ "`resource_based_options` must be set if any slot options are ResourceBased"
139
+ .to_string(),
140
+ );
141
+ }
142
+ Ok(())
143
+ }
144
+ }
145
+
26
146
  /// Can be used to construct a `TunerHolder` from individual slot suppliers. Any supplier which is
27
147
  /// not provided will default to a [FixedSizeSlotSupplier] with a capacity of 100.
28
148
  #[derive(Default, Clone)]
@@ -78,8 +198,8 @@ impl TunerBuilder {
78
198
  }
79
199
 
80
200
  /// Build a [WorkerTuner] from the configured slot suppliers
81
- pub fn build(&mut self) -> Arc<dyn WorkerTuner + Send + Sync> {
82
- Arc::new(TunerHolder {
201
+ pub fn build(&mut self) -> TunerHolder {
202
+ TunerHolder {
83
203
  wft_supplier: self
84
204
  .workflow_slot_supplier
85
205
  .clone()
@@ -93,7 +213,7 @@ impl TunerBuilder {
93
213
  .clone()
94
214
  .unwrap_or_else(|| Arc::new(FixedSizeSlotSupplier::new(100))),
95
215
  metrics: OnceLock::new(),
96
- })
216
+ }
97
217
  }
98
218
  }
99
219
 
@@ -41,7 +41,7 @@ impl DrivenWorkflow {
41
41
  ) {
42
42
  debug!(run_id = %attribs.original_execution_run_id, "Driven WF start");
43
43
  let started_info = WorkflowStartedInfo {
44
- workflow_task_timeout: attribs.workflow_task_timeout.clone().try_into_or_none(),
44
+ workflow_task_timeout: attribs.workflow_task_timeout.try_into_or_none(),
45
45
  memo: attribs.memo.clone(),
46
46
  search_attrs: attribs.search_attributes.clone(),
47
47
  retry_policy: attribs.retry_policy.clone(),
@@ -5,7 +5,7 @@ use crate::{
5
5
  workflow::{CacheMissFetchReq, PermittedWFT, PreparedWFT},
6
6
  },
7
7
  };
8
- use futures::{future::BoxFuture, FutureExt, Stream};
8
+ use futures::{future::BoxFuture, FutureExt, Stream, TryFutureExt};
9
9
  use itertools::Itertools;
10
10
  use once_cell::sync::Lazy;
11
11
  use std::{
@@ -65,6 +65,12 @@ impl Debug for HistoryUpdate {
65
65
  }
66
66
  }
67
67
 
68
+ impl HistoryUpdate {
69
+ pub(crate) fn get_events(&self) -> &[HistoryEvent] {
70
+ &self.events
71
+ }
72
+ }
73
+
68
74
  #[derive(Debug)]
69
75
  pub(crate) enum NextWFT {
70
76
  ReplayOver,
@@ -402,7 +408,10 @@ impl Stream for StreamingHistoryPaginator {
402
408
  // SAFETY: This is safe because the inner paginator cannot be dropped before the future,
403
409
  // and the future won't be moved from out of this struct.
404
410
  this.open_history_request.set(Some(unsafe {
405
- transmute(HistoryPaginator::get_next_page(this.inner).boxed())
411
+ transmute::<
412
+ BoxFuture<'_, Result<(), tonic::Status>>,
413
+ BoxFuture<'static, Result<(), tonic::Status>>,
414
+ >(this.inner.get_next_page().map_ok(|_| ()).boxed())
406
415
  }));
407
416
  }
408
417
  let history_req = this.open_history_request.as_mut().as_pin_mut().unwrap();
@@ -134,6 +134,7 @@ impl ActivityMachine {
134
134
  s.shared_state().attrs.clone(),
135
135
  use_compatible_version,
136
136
  )),
137
+ user_metadata: Default::default(),
137
138
  };
138
139
  NewMachineWithCommand {
139
140
  command,
@@ -406,7 +407,7 @@ impl ScheduleCommandCreated {
406
407
 
407
408
  pub(super) fn on_abandoned(self, dat: &mut SharedState) -> ActivityMachineTransition<Canceled> {
408
409
  dat.cancelled_before_sent = true;
409
- ActivityMachineTransition::default()
410
+ notify_lang_activity_cancelled(None)
410
411
  }
411
412
  }
412
413
 
@@ -687,6 +688,7 @@ where
687
688
  },
688
689
  ),
689
690
  ),
691
+ user_metadata: Default::default(),
690
692
  };
691
693
  ActivityMachineTransition::ok(
692
694
  vec![ActivityMachineCommand::RequestCancellation(cmd)],
@@ -804,7 +806,7 @@ mod test {
804
806
  internal_flags::InternalFlags,
805
807
  replay::TestHistoryBuilder,
806
808
  test_help::{build_fake_sdk, MockPollCfg, ResponseType},
807
- worker::workflow::machines::Machines,
809
+ worker::workflow::{machines::Machines, OutgoingJob},
808
810
  };
809
811
  use std::{cell::RefCell, mem::discriminant, rc::Rc};
810
812
  use temporal_sdk::{ActivityOptions, CancellableFuture, WfContext, WorkflowFunction};
@@ -903,7 +905,20 @@ mod test {
903
905
  panic!("Wrong machine type");
904
906
  };
905
907
  let cmds = s.cancel().unwrap();
906
- assert_eq!(cmds.len(), 0);
908
+ // We should always be notifying lang that the activity got cancelled, even if it's
909
+ // abandoned and we aren't telling server
910
+ assert_matches!(
911
+ cmds.as_slice(),
912
+ [MachineResponse::PushWFJob(OutgoingJob {
913
+ variant: workflow_activation_job::Variant::ResolveActivity(ResolveActivity {
914
+ result: Some(ActivityResolution {
915
+ status: Some(activity_resolution::Status::Cancelled(_))
916
+ }),
917
+ ..
918
+ }),
919
+ ..
920
+ })]
921
+ );
907
922
  let curstate = s.state();
908
923
  assert!(matches!(curstate, &ActivityMachineState::Canceled(_)));
909
924
  }
@@ -78,6 +78,7 @@ pub(super) fn new_external_cancel(
78
78
  let cmd = Command {
79
79
  command_type: CommandType::RequestCancelExternalWorkflowExecution as i32,
80
80
  attributes: Some(cmd_attrs),
81
+ user_metadata: Default::default(),
81
82
  };
82
83
  NewMachineWithCommand {
83
84
  command: cmd,
@@ -37,6 +37,7 @@ pub(super) fn cancel_workflow(attribs: CancelWorkflowExecution) -> NewMachineWit
37
37
  let command = Command {
38
38
  command_type: CommandType::CancelWorkflowExecution as i32,
39
39
  attributes: Some(attribs.into()),
40
+ user_metadata: Default::default(),
40
41
  };
41
42
  NewMachineWithCommand {
42
43
  command,
@@ -457,6 +457,7 @@ impl ChildWorkflowMachine {
457
457
  attribs,
458
458
  use_compatible_version,
459
459
  )),
460
+ user_metadata: Default::default(),
460
461
  };
461
462
  NewMachineWithCommand {
462
463
  command: cmd,
@@ -97,6 +97,7 @@ impl Created {
97
97
  let cmd = Command {
98
98
  command_type: CommandType::CompleteWorkflowExecution as i32,
99
99
  attributes: Some(self.attribs.into()),
100
+ user_metadata: Default::default(),
100
101
  };
101
102
  TransitionResult::commands(vec![CompleteWFCommand::AddCommand(cmd)])
102
103
  }
@@ -40,6 +40,7 @@ pub(super) fn continue_as_new(
40
40
  let command = Command {
41
41
  command_type: CommandType::ContinueAsNewWorkflowExecution as i32,
42
42
  attributes: Some(continue_as_new_cmd_to_api(attribs, use_compatible_version)),
43
+ user_metadata: Default::default(),
43
44
  };
44
45
  NewMachineWithCommand {
45
46
  command,
@@ -64,6 +64,7 @@ impl Created {
64
64
  let cmd = ProtoCommand {
65
65
  command_type: CommandType::FailWorkflowExecution as i32,
66
66
  attributes: Some(self.attribs.into()),
67
+ user_metadata: Default::default(),
67
68
  };
68
69
  TransitionResult::commands(vec![FailWFCommand::AddCommand(cmd)])
69
70
  }
@@ -674,7 +674,7 @@ impl WFMachinesAdapter for LocalActivityMachine {
674
674
  status: Some(
675
675
  DoBackoff {
676
676
  attempt: attempt + 1,
677
- backoff_duration: Some(b.clone()),
677
+ backoff_duration: Some(*b),
678
678
  original_schedule_time: original_schedule_time.map(Into::into),
679
679
  }
680
680
  .into(),
@@ -882,7 +882,7 @@ mod tests {
882
882
  time::Duration,
883
883
  };
884
884
  use temporal_sdk::{
885
- ActContext, ActivityCancelledError, CancellableFuture, LocalActivityOptions, WfContext,
885
+ ActContext, ActivityError, CancellableFuture, LocalActivityOptions, WfContext,
886
886
  WorkflowResult,
887
887
  };
888
888
  use temporal_sdk_core_protos::{
@@ -988,7 +988,7 @@ mod tests {
988
988
  if completes_ok {
989
989
  Ok("hi")
990
990
  } else {
991
- Err(anyhow!("Oh no I failed!"))
991
+ Err(anyhow!("Oh no I failed!").into())
992
992
  }
993
993
  },
994
994
  );
@@ -1450,7 +1450,7 @@ mod tests {
1450
1450
  ctx.cancelled().await;
1451
1451
  }
1452
1452
  allow_cancel_barr_clone.cancelled().await;
1453
- Result::<(), _>::Err(anyhow!(ActivityCancelledError::default()))
1453
+ Result::<(), _>::Err(ActivityError::cancelled())
1454
1454
  }
1455
1455
  });
1456
1456
  worker.run().await.unwrap();
@@ -31,6 +31,7 @@ pub(super) fn modify_workflow_properties(
31
31
  let cmd = Command {
32
32
  command_type: CommandType::ModifyWorkflowProperties as i32,
33
33
  attributes: Some(lang_cmd.into()),
34
+ user_metadata: Default::default(),
34
35
  };
35
36
  NewMachineWithCommand {
36
37
  command: cmd,
@@ -114,6 +114,7 @@ pub(super) fn has_change<'a>(
114
114
  }
115
115
  .into(),
116
116
  ),
117
+ user_metadata: Default::default(),
117
118
  };
118
119
  let mut machine = PatchMachine::from_parts(initial_state, shared_state);
119
120
 
@@ -112,6 +112,7 @@ pub(super) fn new_external_signal(
112
112
  let cmd = Command {
113
113
  command_type: CommandType::SignalExternalWorkflowExecution as i32,
114
114
  attributes: Some(cmd_attrs),
115
+ user_metadata: Default::default(),
115
116
  };
116
117
  Ok(NewMachineWithCommand {
117
118
  command: cmd,
@@ -78,7 +78,8 @@ impl TimerMachine {
78
78
  .expect("Scheduling timers doesn't fail");
79
79
  let cmd = Command {
80
80
  command_type: CommandType::StartTimer as i32,
81
- attributes: Some(s.shared_state().attrs.clone().into()),
81
+ attributes: Some(s.shared_state().attrs.into()),
82
+ user_metadata: Default::default(),
82
83
  };
83
84
  (s, cmd)
84
85
  }
@@ -210,6 +211,7 @@ impl StartCommandRecorded {
210
211
  let cmd = Command {
211
212
  command_type: CommandType::CancelTimer as i32,
212
213
  attributes: Some(CancelTimer { seq: dat.attrs.seq }.into()),
214
+ user_metadata: Default::default(),
213
215
  };
214
216
  TransitionResult::ok(
215
217
  vec![TimerMachineCommand::IssueCancelCmd(cmd)],