@temporalio/core-bridge 1.13.0 → 1.13.2

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 (181) hide show
  1. package/Cargo.lock +239 -382
  2. package/Cargo.toml +11 -11
  3. package/lib/native.d.ts +10 -3
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.cargo/config.toml +71 -11
  11. package/sdk-core/.clippy.toml +1 -0
  12. package/sdk-core/.github/workflows/heavy.yml +2 -0
  13. package/sdk-core/.github/workflows/per-pr.yml +50 -18
  14. package/sdk-core/ARCHITECTURE.md +44 -48
  15. package/sdk-core/Cargo.toml +26 -7
  16. package/sdk-core/README.md +4 -0
  17. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  18. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  19. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  20. package/sdk-core/client/Cargo.toml +8 -7
  21. package/sdk-core/client/src/callback_based.rs +1 -2
  22. package/sdk-core/client/src/lib.rs +485 -299
  23. package/sdk-core/client/src/metrics.rs +32 -8
  24. package/sdk-core/client/src/proxy.rs +124 -5
  25. package/sdk-core/client/src/raw.rs +598 -307
  26. package/sdk-core/client/src/replaceable.rs +253 -0
  27. package/sdk-core/client/src/retry.rs +9 -6
  28. package/sdk-core/client/src/worker_registry/mod.rs +19 -3
  29. package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
  30. package/sdk-core/core/Cargo.toml +100 -31
  31. package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
  32. package/sdk-core/core/src/core_tests/mod.rs +2 -8
  33. package/sdk-core/core/src/core_tests/queries.rs +3 -5
  34. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
  35. package/sdk-core/core/src/core_tests/updates.rs +4 -5
  36. package/sdk-core/core/src/core_tests/workers.rs +4 -3
  37. package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
  38. package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
  39. package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
  40. package/sdk-core/core/src/internal_flags.rs +11 -1
  41. package/sdk-core/core/src/lib.rs +50 -36
  42. package/sdk-core/core/src/pollers/mod.rs +5 -5
  43. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  44. package/sdk-core/core/src/protosext/mod.rs +13 -5
  45. package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
  46. package/sdk-core/core/src/retry_logic.rs +256 -108
  47. package/sdk-core/core/src/telemetry/metrics.rs +1 -0
  48. package/sdk-core/core/src/telemetry/mod.rs +8 -2
  49. package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
  50. package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
  51. package/sdk-core/core/src/test_help/mod.rs +10 -1100
  52. package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
  53. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
  55. package/sdk-core/core/src/worker/activities.rs +10 -3
  56. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  57. package/sdk-core/core/src/worker/client.rs +130 -93
  58. package/sdk-core/core/src/worker/heartbeat.rs +12 -13
  59. package/sdk-core/core/src/worker/mod.rs +31 -21
  60. package/sdk-core/core/src/worker/nexus.rs +14 -3
  61. package/sdk-core/core/src/worker/slot_provider.rs +9 -0
  62. package/sdk-core/core/src/worker/tuner.rs +159 -0
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
  64. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
  65. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
  66. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
  67. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
  68. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
  69. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
  71. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
  72. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
  73. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
  74. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
  75. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
  76. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
  77. package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
  78. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
  79. package/sdk-core/core-api/Cargo.toml +4 -4
  80. package/sdk-core/core-api/src/envconfig.rs +153 -54
  81. package/sdk-core/core-api/src/lib.rs +68 -0
  82. package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
  83. package/sdk-core/core-api/src/telemetry.rs +13 -0
  84. package/sdk-core/core-c-bridge/Cargo.toml +13 -8
  85. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
  86. package/sdk-core/core-c-bridge/src/client.rs +462 -184
  87. package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
  88. package/sdk-core/core-c-bridge/src/lib.rs +1 -0
  89. package/sdk-core/core-c-bridge/src/random.rs +4 -4
  90. package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
  91. package/sdk-core/core-c-bridge/src/testing.rs +1 -4
  92. package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
  93. package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
  94. package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
  95. package/sdk-core/core-c-bridge/src/worker.rs +319 -66
  96. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
  98. package/sdk-core/sdk/Cargo.toml +8 -2
  99. package/sdk-core/sdk/src/activity_context.rs +1 -1
  100. package/sdk-core/sdk/src/app_data.rs +1 -1
  101. package/sdk-core/sdk/src/interceptors.rs +1 -4
  102. package/sdk-core/sdk/src/lib.rs +1 -5
  103. package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
  104. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  105. package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
  106. package/sdk-core/sdk-core-protos/build.rs +10 -23
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  116. package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
  117. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
  118. package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
  119. package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
  120. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
  121. package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  122. package/sdk-core/tests/cloud_tests.rs +10 -8
  123. package/sdk-core/tests/common/http_proxy.rs +134 -0
  124. package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
  125. package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
  126. package/sdk-core/tests/fuzzy_workflow.rs +1 -1
  127. package/sdk-core/tests/global_metric_tests.rs +8 -7
  128. package/sdk-core/tests/heavy_tests.rs +7 -3
  129. package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
  130. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
  131. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
  132. package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
  133. package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  134. package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
  135. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  136. package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
  137. package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
  138. package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
  139. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
  140. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
  141. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
  144. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
  145. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
  146. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
  147. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  148. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
  149. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
  150. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
  151. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
  152. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
  153. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
  154. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
  155. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
  156. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
  157. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
  158. package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
  159. package/sdk-core/tests/main.rs +26 -17
  160. package/sdk-core/tests/manual_tests.rs +5 -1
  161. package/sdk-core/tests/runner.rs +22 -40
  162. package/sdk-core/tests/shared_tests/mod.rs +1 -1
  163. package/sdk-core/tests/shared_tests/priority.rs +1 -1
  164. package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
  165. package/src/client.rs +97 -20
  166. package/src/helpers/callbacks.rs +4 -4
  167. package/src/helpers/errors.rs +7 -1
  168. package/src/helpers/handles.rs +1 -0
  169. package/src/helpers/try_from_js.rs +4 -3
  170. package/src/lib.rs +3 -2
  171. package/src/metrics.rs +3 -0
  172. package/src/runtime.rs +5 -2
  173. package/src/worker.rs +9 -12
  174. package/ts/native.ts +13 -3
  175. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  176. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  177. package/sdk-core/core/src/core_tests/determinism.rs +0 -318
  178. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  179. package/sdk-core/test-utils/Cargo.toml +0 -38
  180. package/sdk-core/test-utils/src/histfetch.rs +0 -28
  181. package/sdk-core/test-utils/src/interceptors.rs +0 -46
@@ -0,0 +1,253 @@
1
+ use crate::NamespacedClient;
2
+ use std::{
3
+ borrow::Cow,
4
+ sync::{
5
+ Arc, RwLock,
6
+ atomic::{AtomicU32, Ordering},
7
+ },
8
+ };
9
+
10
+ /// A client wrapper that allows replacing the underlying client at a later point in time.
11
+ /// Clones of this struct have a shared reference to the underlying client, and each clone also
12
+ /// has its own cached clone of the underlying client. Before every service call, a check is made
13
+ /// whether the shared client was replaced, and the cached clone is updated accordingly.
14
+ ///
15
+ /// This struct is fully thread-safe, and it works in a lock-free manner except when the client is
16
+ /// being replaced. A read-write lock is used then, with minimal locking time.
17
+ #[derive(Debug)]
18
+ pub struct SharedReplaceableClient<C>
19
+ where
20
+ C: Clone + Send + Sync,
21
+ {
22
+ shared_data: Arc<SharedClientData<C>>,
23
+ cloned_client: C,
24
+ cloned_generation: u32,
25
+ }
26
+
27
+ #[derive(Debug)]
28
+ struct SharedClientData<C>
29
+ where
30
+ C: Clone + Send + Sync,
31
+ {
32
+ client: RwLock<C>,
33
+ generation: AtomicU32,
34
+ }
35
+
36
+ impl<C> SharedClientData<C>
37
+ where
38
+ C: Clone + Send + Sync,
39
+ {
40
+ fn fetch(&self) -> (C, u32) {
41
+ let lock = self.client.read().unwrap();
42
+ let client = lock.clone();
43
+ // Loading generation under lock to ensure the client won't be updated in the meantime.
44
+ let generation = self.generation.load(Ordering::Acquire);
45
+ (client, generation)
46
+ }
47
+
48
+ fn fetch_newer_than(&self, current_generation: u32) -> Option<(C, u32)> {
49
+ // fetch() will do a second atomic load, but it's necessary to avoid a race condition.
50
+ (current_generation != self.generation.load(Ordering::Acquire)).then(|| self.fetch())
51
+ }
52
+
53
+ fn replace_client(&self, client: C) {
54
+ let mut lock = self.client.write().unwrap();
55
+ *lock = client;
56
+ // Updating generation under lock to guarantee consistency when multiple threads replace the
57
+ // client at the same time. The client stored last is always the one with latest generation.
58
+ self.generation.fetch_add(1, Ordering::AcqRel);
59
+ }
60
+ }
61
+
62
+ impl<C> SharedReplaceableClient<C>
63
+ where
64
+ C: Clone + Send + Sync,
65
+ {
66
+ /// Creates the initial instance of replaceable client with the provided underlying client.
67
+ /// Use [`clone()`](Self::clone) method to create more instances that share the same underlying client.
68
+ pub fn new(client: C) -> Self {
69
+ let cloned_client = client.clone();
70
+ Self {
71
+ shared_data: Arc::new(SharedClientData {
72
+ client: RwLock::new(client),
73
+ generation: AtomicU32::new(0),
74
+ }),
75
+ cloned_client,
76
+ cloned_generation: 0,
77
+ }
78
+ }
79
+
80
+ /// Replaces the client for all instances that share this instance's underlying client.
81
+ pub fn replace_client(&self, new_client: C) {
82
+ self.shared_data.replace_client(new_client); // cloned_client will be updated on next mutable call
83
+ }
84
+
85
+ /// Returns a clone of the underlying client.
86
+ pub fn inner_clone(&self) -> C {
87
+ self.inner_cow().into_owned()
88
+ }
89
+
90
+ /// Returns an immutable reference to this instance's cached clone of the underlying client if
91
+ /// it's up to date, or a fresh clone of the shared client otherwise. Because it's an immutable
92
+ /// method, it will not update this instance's cached clone. For this reason, prefer to use
93
+ /// [`inner_mut_refreshed()`](Self::inner_mut_refreshed) when possible.
94
+ pub fn inner_cow(&self) -> Cow<'_, C> {
95
+ self.shared_data
96
+ .fetch_newer_than(self.cloned_generation)
97
+ .map(|(c, _)| Cow::Owned(c))
98
+ .unwrap_or_else(|| Cow::Borrowed(&self.cloned_client))
99
+ }
100
+
101
+ /// Returns a mutable reference to this instance's cached clone of the underlying client. If the
102
+ /// cached clone is not up to date, it's refreshed before the reference is returned. This method
103
+ /// is called automatically by most other mutable methods, in particular by all service calls,
104
+ /// so most of the time it doesn't need to be called directly.
105
+ ///
106
+ /// While this method allows mutable access to the underlying client, any configuration changes
107
+ /// will not be shared with other instances, and will be lost if the client gets replaced from
108
+ /// anywhere. To make configuration changes, use [`replace_client()`](Self::replace_client) instead.
109
+ pub fn inner_mut_refreshed(&mut self) -> &mut C {
110
+ if let Some((client, generation)) =
111
+ self.shared_data.fetch_newer_than(self.cloned_generation)
112
+ {
113
+ self.cloned_client = client;
114
+ self.cloned_generation = generation;
115
+ }
116
+ &mut self.cloned_client
117
+ }
118
+ }
119
+
120
+ impl<C> Clone for SharedReplaceableClient<C>
121
+ where
122
+ C: Clone + Send + Sync,
123
+ {
124
+ /// Creates a new instance of replaceable client that shares the underlying client with this
125
+ /// instance. Replacing a client in either instance will replace it for both instances, and all
126
+ /// other clones too.
127
+ fn clone(&self) -> Self {
128
+ // self's cloned_client could've been modified through a mutable reference,
129
+ // so for consistent behavior, we need to fetch it from shared_data.
130
+ let (client, generation) = self.shared_data.fetch();
131
+ Self {
132
+ shared_data: self.shared_data.clone(),
133
+ cloned_client: client,
134
+ cloned_generation: generation,
135
+ }
136
+ }
137
+ }
138
+
139
+ impl<C> NamespacedClient for SharedReplaceableClient<C>
140
+ where
141
+ C: NamespacedClient + Clone + Send + Sync,
142
+ {
143
+ fn namespace(&self) -> String {
144
+ self.inner_cow().namespace()
145
+ }
146
+
147
+ fn identity(&self) -> String {
148
+ self.inner_cow().identity()
149
+ }
150
+ }
151
+
152
+ #[cfg(test)]
153
+ mod tests {
154
+ use super::*;
155
+ use crate::NamespacedClient;
156
+ use std::borrow::Cow;
157
+
158
+ #[derive(Debug, Clone)]
159
+ struct StubClient {
160
+ identity: String,
161
+ }
162
+
163
+ impl StubClient {
164
+ fn new(identity: &str) -> Self {
165
+ Self {
166
+ identity: identity.to_owned(),
167
+ }
168
+ }
169
+ }
170
+
171
+ impl NamespacedClient for StubClient {
172
+ fn namespace(&self) -> String {
173
+ "default".into()
174
+ }
175
+
176
+ fn identity(&self) -> String {
177
+ self.identity.clone()
178
+ }
179
+ }
180
+
181
+ #[test]
182
+ fn cow_returns_reference_before_and_clone_after_refresh() {
183
+ let mut client = SharedReplaceableClient::new(StubClient::new("1"));
184
+ let Cow::Borrowed(inner) = client.inner_cow() else {
185
+ panic!("expected borrowed inner");
186
+ };
187
+ assert_eq!(inner.identity, "1");
188
+
189
+ client.replace_client(StubClient::new("2"));
190
+ let Cow::Owned(inner) = client.inner_cow() else {
191
+ panic!("expected owned inner");
192
+ };
193
+ assert_eq!(inner.identity, "2");
194
+
195
+ assert_eq!(client.inner_mut_refreshed().identity, "2");
196
+ let Cow::Borrowed(inner) = client.inner_cow() else {
197
+ panic!("expected borrowed inner");
198
+ };
199
+ assert_eq!(inner.identity, "2");
200
+ }
201
+
202
+ #[test]
203
+ fn client_replaced_in_clones() {
204
+ let original1 = SharedReplaceableClient::new(StubClient::new("1"));
205
+ let clone1 = original1.clone();
206
+ assert_eq!(original1.identity(), "1");
207
+ assert_eq!(clone1.identity(), "1");
208
+
209
+ original1.replace_client(StubClient::new("2"));
210
+ assert_eq!(original1.identity(), "2");
211
+ assert_eq!(clone1.identity(), "2");
212
+
213
+ let original2 = SharedReplaceableClient::new(StubClient::new("3"));
214
+ let clone2 = original2.clone();
215
+ assert_eq!(original2.identity(), "3");
216
+ assert_eq!(clone2.identity(), "3");
217
+
218
+ clone2.replace_client(StubClient::new("4"));
219
+ assert_eq!(original2.identity(), "4");
220
+ assert_eq!(clone2.identity(), "4");
221
+ assert_eq!(original1.identity(), "2");
222
+ assert_eq!(clone1.identity(), "2");
223
+ }
224
+
225
+ #[test]
226
+ fn client_replaced_from_multiple_threads() {
227
+ let mut client = SharedReplaceableClient::new(StubClient::new("original"));
228
+ std::thread::scope(|scope| {
229
+ for thread_no in 0..100 {
230
+ let mut client = client.clone();
231
+ scope.spawn(move || {
232
+ for i in 0..1000 {
233
+ let old_generation = client.cloned_generation;
234
+ client.inner_mut_refreshed();
235
+ let current_generation = client.cloned_generation;
236
+ assert!(current_generation >= old_generation);
237
+ let replace_identity = format!("{thread_no}-{i}");
238
+ client.replace_client(StubClient::new(&replace_identity));
239
+ client.inner_mut_refreshed();
240
+ assert!(client.cloned_generation > current_generation);
241
+ let refreshed_identity = client.identity();
242
+ if refreshed_identity.split('-').next().unwrap() == thread_no.to_string() {
243
+ assert_eq!(replace_identity, refreshed_identity);
244
+ }
245
+ }
246
+ });
247
+ }
248
+ });
249
+ client.inner_mut_refreshed();
250
+ assert_eq!(client.cloned_generation, 100_000);
251
+ assert!(client.identity().ends_with("-999"));
252
+ }
253
+ }
@@ -1,5 +1,5 @@
1
1
  use crate::{
2
- Client, ERROR_RETURNED_DUE_TO_SHORT_CIRCUIT, IsWorkerTaskLongPoll, MESSAGE_TOO_LARGE_KEY,
2
+ ERROR_RETURNED_DUE_TO_SHORT_CIRCUIT, IsWorkerTaskLongPoll, MESSAGE_TOO_LARGE_KEY,
3
3
  NamespacedClient, NoRetryOnMatching, Result, RetryConfig, raw::IsUserLongPoll,
4
4
  };
5
5
  use backoff::{Clock, SystemClock, backoff::Backoff, exponential::ExponentialBackoff};
@@ -98,13 +98,16 @@ impl<SG> RetryClient<SG> {
98
98
  }
99
99
  }
100
100
 
101
- impl NamespacedClient for RetryClient<Client> {
102
- fn namespace(&self) -> &str {
103
- &self.client.namespace
101
+ impl<SG> NamespacedClient for RetryClient<SG>
102
+ where
103
+ SG: NamespacedClient,
104
+ {
105
+ fn namespace(&self) -> String {
106
+ self.client.namespace()
104
107
  }
105
108
 
106
- fn get_identity(&self) -> &str {
107
- &self.client.options().identity
109
+ fn identity(&self) -> String {
110
+ self.client.identity()
108
111
  }
109
112
  }
110
113
 
@@ -22,6 +22,8 @@ pub trait SlotProvider: std::fmt::Debug {
22
22
  fn task_queue(&self) -> &str;
23
23
  /// Try to reserve a slot on this worker.
24
24
  fn try_reserve_wft_slot(&self) -> Option<Box<dyn Slot + Send>>;
25
+ /// Get the worker deployment options for this worker, if using deployment-based versioning.
26
+ fn deployment_options(&self) -> Option<temporal_sdk_core_api::worker::WorkerDeploymentOptions>;
25
27
  }
26
28
 
27
29
  /// This trait represents a slot reserved for processing a WFT by a worker.
@@ -34,6 +36,14 @@ pub trait Slot {
34
36
  ) -> Result<(), anyhow::Error>;
35
37
  }
36
38
 
39
+ /// Result of reserving a workflow task slot, including deployment options if applicable.
40
+ pub(crate) struct SlotReservation {
41
+ /// The reserved slot for processing the workflow task
42
+ pub slot: Box<dyn Slot + Send>,
43
+ /// Worker deployment options, if the worker is using deployment-based versioning
44
+ pub deployment_options: Option<temporal_sdk_core_api::worker::WorkerDeploymentOptions>,
45
+ }
46
+
37
47
  #[derive(PartialEq, Eq, Hash, Debug, Clone)]
38
48
  struct SlotKey {
39
49
  namespace: String,
@@ -71,12 +81,16 @@ impl SlotManagerImpl {
71
81
  &self,
72
82
  namespace: String,
73
83
  task_queue: String,
74
- ) -> Option<Box<dyn Slot + Send>> {
84
+ ) -> Option<SlotReservation> {
75
85
  let key = SlotKey::new(namespace, task_queue);
76
86
  if let Some(p) = self.providers.get(&key)
77
87
  && let Some(slot) = p.try_reserve_wft_slot()
78
88
  {
79
- return Some(slot);
89
+ let deployment_options = p.deployment_options();
90
+ return Some(SlotReservation {
91
+ slot,
92
+ deployment_options,
93
+ });
80
94
  }
81
95
  None
82
96
  }
@@ -126,11 +140,12 @@ impl SlotManager {
126
140
  }
127
141
 
128
142
  /// Try to reserve a compatible processing slot in any of the registered workers.
143
+ /// Returns the slot and the worker's deployment options (if using deployment-based versioning).
129
144
  pub(crate) fn try_reserve_wft_slot(
130
145
  &self,
131
146
  namespace: String,
132
147
  task_queue: String,
133
- ) -> Option<Box<dyn Slot + Send>> {
148
+ ) -> Option<SlotReservation> {
134
149
  self.manager
135
150
  .read()
136
151
  .try_reserve_wft_slot(namespace, task_queue)
@@ -188,6 +203,7 @@ mod tests {
188
203
  });
189
204
  mock_provider.expect_namespace().return_const(namespace);
190
205
  mock_provider.expect_task_queue().return_const(task_queue);
206
+ mock_provider.expect_deployment_options().return_const(None);
191
207
  mock_provider
192
208
  }
193
209
 
@@ -1,4 +1,4 @@
1
- use crate::{InterceptedMetricsSvc, RawClientLike, WorkflowService};
1
+ use crate::WorkflowService;
2
2
  use anyhow::{anyhow, bail};
3
3
  use std::{fmt::Debug, marker::PhantomData};
4
4
  use temporal_sdk_core_protos::{
@@ -11,6 +11,7 @@ use temporal_sdk_core_protos::{
11
11
  workflowservice::v1::GetWorkflowExecutionHistoryRequest,
12
12
  },
13
13
  };
14
+ use tonic::IntoRequest;
14
15
 
15
16
  /// Enumerates terminal states for a particular workflow execution
16
17
  // TODO: Add non-proto failure types, flesh out details, etc.
@@ -81,7 +82,7 @@ impl WorkflowExecutionInfo {
81
82
  /// Bind the workflow info to a specific client, turning it into a workflow handle
82
83
  pub fn bind_untyped<CT>(self, client: CT) -> UntypedWorkflowHandle<CT>
83
84
  where
84
- CT: RawClientLike<SvcType = InterceptedMetricsSvc> + Clone,
85
+ CT: WorkflowService + Clone,
85
86
  {
86
87
  UntypedWorkflowHandle::new(client, self)
87
88
  }
@@ -92,7 +93,7 @@ pub(crate) type UntypedWorkflowHandle<CT> = WorkflowHandle<CT, Vec<Payload>>;
92
93
 
93
94
  impl<CT, RT> WorkflowHandle<CT, RT>
94
95
  where
95
- CT: RawClientLike<SvcType = InterceptedMetricsSvc> + Clone,
96
+ CT: WorkflowService + Clone,
96
97
  // TODO: Make more generic, capable of (de)serialization w/ serde
97
98
  RT: FromPayloadsExt,
98
99
  {
@@ -125,18 +126,21 @@ where
125
126
  let server_res = self
126
127
  .client
127
128
  .clone()
128
- .get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
129
- namespace: self.info.namespace.to_string(),
130
- execution: Some(WorkflowExecution {
131
- workflow_id: self.info.workflow_id.clone(),
132
- run_id: run_id.clone(),
133
- }),
134
- skip_archival: true,
135
- wait_new_event: true,
136
- history_event_filter_type: HistoryEventFilterType::CloseEvent as i32,
137
- next_page_token: next_page_tok.clone(),
138
- ..Default::default()
139
- })
129
+ .get_workflow_execution_history(
130
+ GetWorkflowExecutionHistoryRequest {
131
+ namespace: self.info.namespace.to_string(),
132
+ execution: Some(WorkflowExecution {
133
+ workflow_id: self.info.workflow_id.clone(),
134
+ run_id: run_id.clone(),
135
+ }),
136
+ skip_archival: true,
137
+ wait_new_event: true,
138
+ history_event_filter_type: HistoryEventFilterType::CloseEvent as i32,
139
+ next_page_token: next_page_tok.clone(),
140
+ ..Default::default()
141
+ }
142
+ .into_request(),
143
+ )
140
144
  .await?
141
145
  .into_inner();
142
146
 
@@ -200,8 +204,7 @@ where
200
204
  o => Err(anyhow!(
201
205
  "Server returned an event that didn't match the CloseEvent filter. \
202
206
  This is either a server bug or a new event the SDK does not understand. \
203
- Event details: {:?}",
204
- o
207
+ Event details: {o:?}"
205
208
  )),
206
209
  };
207
210
  }
@@ -1,7 +1,10 @@
1
1
  [package]
2
2
  name = "temporal-sdk-core"
3
3
  version = "0.1.0"
4
- authors = ["Spencer Judge <spencer@temporal.io>", "Vitaly Arbuzov <vitaly@temporal.io>"]
4
+ authors = [
5
+ "Spencer Judge <spencer@temporal.io>",
6
+ "Vitaly Arbuzov <vitaly@temporal.io>",
7
+ ]
5
8
  edition = "2024"
6
9
  license-file = { workspace = true }
7
10
  description = "Library for building new Temporal SDKs"
@@ -14,64 +17,107 @@ categories = ["development-tools"]
14
17
 
15
18
  [features]
16
19
  default = ["otel", "prom"]
17
- otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp", "dep:hyper",
18
- "dep:hyper-util", "dep:http-body-util"]
20
+ otel = [
21
+ "dep:opentelemetry",
22
+ "dep:opentelemetry_sdk",
23
+ "dep:opentelemetry-otlp",
24
+ "dep:hyper",
25
+ "dep:hyper-util",
26
+ "dep:http-body-util",
27
+ ]
19
28
  prom = ["dep:prometheus"]
20
29
  tokio-console = ["console-subscriber"]
21
30
  ephemeral-server = ["dep:flate2", "dep:reqwest", "dep:tar", "dep:zip"]
22
31
  debug-plugin = ["dep:reqwest"]
32
+ test-utilities = ["dep:assert_matches", "dep:bimap"]
23
33
 
24
34
  [dependencies]
25
35
  anyhow = "1.0"
36
+ assert_matches = { version = "1.5", optional = true }
37
+ bimap = { version = "0.6.3", optional = true }
26
38
  async-trait = "0.1"
27
39
  console-subscriber = { version = "0.4", optional = true }
28
40
  crossbeam-channel = "0.5"
29
41
  crossbeam-queue = "0.3"
30
42
  crossbeam-utils = "0.8"
31
- dashmap = "6.0"
43
+ dashmap = "6.1"
32
44
  derive_builder = { workspace = true }
33
45
  derive_more = { workspace = true }
34
46
  enum_dispatch = "0.3"
35
47
  enum-iterator = "2"
36
- flate2 = { version = "1.0", optional = true }
48
+ flate2 = { version = "1.1", optional = true }
37
49
  futures-util = { version = "0.3", default-features = false }
38
- futures-channel = { version = "0.3", default-features = false, features = ["std"] }
50
+ futures-channel = { version = "0.3", default-features = false, features = [
51
+ "std",
52
+ ] }
39
53
  gethostname = "1.0.2"
40
- governor = "0.8"
54
+ governor = "0.10"
41
55
  http-body-util = { version = "0.1", optional = true }
42
- hyper = { version = "1.2", optional = true }
43
- hyper-util = { version = "0.1", features = ["server", "http1", "http2", "tokio"], optional = true }
56
+ hyper = { version = "1.7", optional = true }
57
+ hyper-util = { version = "0.1", features = [
58
+ "server",
59
+ "http1",
60
+ "http2",
61
+ "tokio",
62
+ ], optional = true }
44
63
  itertools = "0.14"
45
- lru = "0.13"
64
+ lru = "0.16"
46
65
  mockall = "0.13"
47
66
  opentelemetry = { workspace = true, features = ["metrics"], optional = true }
48
- opentelemetry_sdk = { version = "0.30", features = ["rt-tokio", "metrics", "spec_unstable_metrics_views"], optional = true }
49
- opentelemetry-otlp = { version = "0.30", features = ["tokio", "metrics", "tls", "http-proto", "grpc-tonic"], optional = true }
67
+ opentelemetry_sdk = { version = "0.31", features = [
68
+ "rt-tokio",
69
+ "metrics",
70
+ "spec_unstable_metrics_views",
71
+ ], optional = true }
72
+ opentelemetry-otlp = { version = "0.31", features = [
73
+ "tokio",
74
+ "metrics",
75
+ "tls",
76
+ "http-proto",
77
+ "grpc-tonic",
78
+ ], optional = true }
50
79
  parking_lot = { version = "0.12", features = ["send_guard"] }
51
80
  pid = "4.0"
52
- pin-project = "1.0"
81
+ pin-project = "1.1"
53
82
  prometheus = { version = "0.14", optional = true }
54
83
  prost = { workspace = true }
55
- prost-types = { version = "0.6", package = "prost-wkt-types" }
84
+ prost-types = { workspace = true }
56
85
  rand = "0.9"
57
- reqwest = { version = "0.12", features = ["json", "stream", "rustls-tls-native-roots"], default-features = false, optional = true }
86
+ reqwest = { version = "0.12", features = [
87
+ "json",
88
+ "stream",
89
+ "rustls-tls-native-roots",
90
+ ], default-features = false, optional = true }
58
91
  ringbuf = "0.4"
59
92
  serde = "1.0"
60
93
  serde_json = "1.0"
61
94
  siphasher = "1.0"
62
95
  slotmap = "1.0"
63
- sysinfo = { version = "0.33", default-features = false, features = ["system"] }
96
+ sysinfo = { version = "0.37", default-features = false, features = ["system"] }
64
97
  tar = { version = "0.4", optional = true }
65
98
  thiserror = { workspace = true }
66
- tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
99
+ tokio = { version = "1.47", features = [
100
+ "rt",
101
+ "rt-multi-thread",
102
+ "parking_lot",
103
+ "time",
104
+ "fs",
105
+ "process",
106
+ ] }
67
107
  tokio-util = { version = "0.7", features = ["io", "io-util"] }
68
108
  tokio-stream = "0.1"
69
109
  tonic = { workspace = true, features = ["tls-ring", "tls-native-roots"] }
70
110
  tracing = "0.1"
71
- tracing-subscriber = { version = "0.3", default-features = false, features = ["parking_lot", "env-filter", "registry", "ansi"] }
72
- url = "2.2"
73
- uuid = { version = "1.1", features = ["v4"] }
74
- zip = { version = "2.0", optional = true }
111
+ tracing-subscriber = { version = "0.3", default-features = false, features = [
112
+ "parking_lot",
113
+ "env-filter",
114
+ "registry",
115
+ "ansi",
116
+ ] }
117
+ url = "2.5"
118
+ uuid = { version = "1.18", features = ["v4"] }
119
+ # Only need specific features to decompress zip files for ephemeral server download
120
+ zip = { version = "4.6", optional = true, default-features = false, features = ["deflate", "bzip2", "zstd"] }
75
121
 
76
122
  # 1st party local deps
77
123
  [dependencies.temporal-sdk-core-api]
@@ -80,7 +126,7 @@ features = ["otel_impls"]
80
126
 
81
127
  [dependencies.temporal-sdk-core-protos]
82
128
  path = "../sdk-core-protos"
83
- features = ["history_builders"]
129
+ features = ["history_builders", "test-utilities"]
84
130
 
85
131
  [dependencies.temporal-client]
86
132
  path = "../client"
@@ -89,14 +135,23 @@ path = "../client"
89
135
  path = "../fsm"
90
136
 
91
137
  [dev-dependencies]
92
- assert_matches = "1.4"
93
- bimap = "0.6.1"
94
- clap = { version = "4.0", features = ["derive"] }
95
- criterion = { version = "0.6", features = ["async", "async_tokio"] }
96
- rstest = "0.25"
97
- temporal-sdk-core-test-utils = { path = "../test-utils" }
138
+ assert_matches = "1.5"
139
+ bimap = "0.6.3"
140
+ bytes = "1.10"
141
+ clap = { version = "4.5", features = ["derive"] }
142
+ criterion = { version = "0.7", features = ["async", "async_tokio"] }
143
+ rstest = "0.26"
144
+ semver = "1.0"
98
145
  temporal-sdk = { path = "../sdk" }
99
- tokio = { version = "1.37", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process", "test-util"] }
146
+ tokio = { version = "1.47", features = [
147
+ "rt",
148
+ "rt-multi-thread",
149
+ "parking_lot",
150
+ "time",
151
+ "fs",
152
+ "process",
153
+ "test-util",
154
+ ] }
100
155
  tokio-stream = { version = "0.1", features = ["net"] }
101
156
 
102
157
  [[test]]
@@ -105,30 +160,39 @@ path = "../tests/main.rs"
105
160
  # Prevents autodiscovery, and hence these getting run with `cargo test`. Run with
106
161
  # `cargo test --test integ_tests`
107
162
  test = false
108
- required-features = ["temporal-sdk-core-protos/serde_serialize"]
163
+ required-features = [
164
+ "temporal-sdk-core-protos/serde_serialize",
165
+ "test-utilities",
166
+ "ephemeral-server",
167
+ ]
109
168
 
110
169
  [[test]]
111
170
  name = "heavy_tests"
112
171
  path = "../tests/heavy_tests.rs"
113
172
  test = false
173
+ required-features = ["test-utilities"]
114
174
 
115
175
  [[test]]
116
176
  name = "manual_tests"
117
177
  path = "../tests/manual_tests.rs"
118
178
  test = false
179
+ required-features = ["test-utilities"]
119
180
 
120
181
  [[test]]
121
182
  name = "global_metric_tests"
122
183
  path = "../tests/global_metric_tests.rs"
123
184
  test = false
185
+ required-features = ["test-utilities"]
124
186
 
125
187
  [[test]]
126
188
  name = "cloud_tests"
127
189
  path = "../tests/cloud_tests.rs"
128
190
  test = false
191
+ required-features = ["test-utilities"]
129
192
 
130
193
  [[bench]]
131
194
  name = "workflow_replay"
195
+ path = "../tests/workflow_replay_bench.rs"
132
196
  harness = false
133
197
 
134
198
  # The integration test runner should compile with the same configuration as the
@@ -140,7 +204,12 @@ name = "integ_runner"
140
204
  path = "../tests/runner.rs"
141
205
  harness = false
142
206
  test = false
143
- required-features = ["temporal-sdk-core-protos/serde_serialize"]
207
+ required-features = [
208
+ "temporal-sdk-core-protos/serde_serialize",
209
+ "test-utilities",
210
+ "ephemeral-server",
211
+ ]
212
+
144
213
 
145
214
  [lints]
146
215
  workspace = true