@temporalio/core-bridge 0.19.2 → 0.20.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 (125) hide show
  1. package/Cargo.lock +90 -157
  2. package/Cargo.toml +1 -0
  3. package/index.d.ts +11 -27
  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/.buildkite/docker/Dockerfile +1 -1
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.cargo/config.toml +1 -0
  13. package/sdk-core/CODEOWNERS +1 -1
  14. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
  15. package/sdk-core/bridge-ffi/src/lib.rs +311 -315
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
  17. package/sdk-core/client/Cargo.toml +13 -9
  18. package/sdk-core/client/LICENSE.txt +23 -0
  19. package/sdk-core/client/src/lib.rs +286 -174
  20. package/sdk-core/client/src/metrics.rs +86 -12
  21. package/sdk-core/client/src/raw.rs +566 -0
  22. package/sdk-core/client/src/retry.rs +137 -99
  23. package/sdk-core/core/Cargo.toml +15 -10
  24. package/sdk-core/core/LICENSE.txt +23 -0
  25. package/sdk-core/core/benches/workflow_replay.rs +79 -0
  26. package/sdk-core/core/src/abstractions.rs +38 -0
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
  29. package/sdk-core/core/src/core_tests/determinism.rs +24 -12
  30. package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
  31. package/sdk-core/core/src/core_tests/mod.rs +30 -43
  32. package/sdk-core/core/src/core_tests/queries.rs +82 -81
  33. package/sdk-core/core/src/core_tests/workers.rs +111 -296
  34. package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
  35. package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
  36. package/sdk-core/core/src/lib.rs +73 -318
  37. package/sdk-core/core/src/pollers/mod.rs +4 -6
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
  39. package/sdk-core/core/src/protosext/mod.rs +7 -10
  40. package/sdk-core/core/src/replay/mod.rs +11 -150
  41. package/sdk-core/core/src/telemetry/metrics.rs +35 -2
  42. package/sdk-core/core/src/telemetry/mod.rs +49 -16
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
  44. package/sdk-core/core/src/test_help/mod.rs +104 -170
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
  46. package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
  47. package/sdk-core/core/src/worker/activities.rs +23 -16
  48. package/sdk-core/core/src/worker/client/mocks.rs +86 -0
  49. package/sdk-core/core/src/worker/client.rs +209 -0
  50. package/sdk-core/core/src/worker/mod.rs +207 -108
  51. package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
  52. package/sdk-core/core/src/workflow/history_update.rs +107 -24
  53. package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
  54. package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
  55. package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
  56. package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
  57. package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
  58. package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
  59. package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
  60. package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
  61. package/sdk-core/core/src/workflow/mod.rs +13 -1
  62. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
  63. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
  64. package/sdk-core/core-api/Cargo.toml +9 -1
  65. package/sdk-core/core-api/LICENSE.txt +23 -0
  66. package/sdk-core/core-api/src/errors.rs +7 -38
  67. package/sdk-core/core-api/src/lib.rs +44 -52
  68. package/sdk-core/core-api/src/worker.rs +10 -2
  69. package/sdk-core/etc/deps.svg +127 -96
  70. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  73. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  80. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  81. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  84. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  85. package/sdk-core/sdk/Cargo.toml +16 -2
  86. package/sdk-core/sdk/LICENSE.txt +23 -0
  87. package/sdk-core/sdk/src/interceptors.rs +11 -0
  88. package/sdk-core/sdk/src/lib.rs +139 -151
  89. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  90. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  91. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  92. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  93. package/sdk-core/sdk-core-protos/build.rs +1 -0
  94. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  95. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  96. package/sdk-core/test-utils/Cargo.toml +3 -1
  97. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  98. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  99. package/sdk-core/test-utils/src/lib.rs +223 -68
  100. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  101. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  102. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  103. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  104. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  106. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  107. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  108. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
  109. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  110. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  111. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  112. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  113. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  114. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  115. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  116. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  117. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  118. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  119. package/sdk-core/tests/load_tests.rs +9 -6
  120. package/sdk-core/tests/main.rs +43 -10
  121. package/src/conversions.rs +7 -12
  122. package/src/lib.rs +322 -357
  123. package/sdk-core/client/src/mocks.rs +0 -167
  124. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  125. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
@@ -1,4 +1,7 @@
1
- use crate::{Result, RetryConfig, ServerGatewayApis, ServerGatewayOptions, WorkflowTaskCompletion};
1
+ use crate::{
2
+ ClientOptions, Result, RetryConfig, WorkflowClientTrait, WorkflowOptions,
3
+ WorkflowTaskCompletion,
4
+ };
2
5
  use backoff::{backoff::Backoff, ExponentialBackoff};
3
6
  use futures_retry::{ErrorHandler, FutureRetry, RetryPolicy};
4
7
  use std::{fmt::Debug, future::Future, time::Duration};
@@ -23,49 +26,88 @@ pub const RETRYABLE_ERROR_CODES: [Code; 7] = [
23
26
  Code::Unavailable,
24
27
  ];
25
28
 
26
- #[derive(Debug)]
27
- /// A wrapper for a [ServerGatewayApis] implementor which performs auto-retries
28
- pub struct RetryGateway<SG> {
29
- gateway: SG,
29
+ /// A wrapper for a [WorkflowClientTrait] or [crate::WorkflowService] implementor which performs
30
+ /// auto-retries
31
+ #[derive(Debug, Clone)]
32
+ pub struct RetryClient<SG> {
33
+ client: SG,
30
34
  retry_config: RetryConfig,
31
35
  }
32
36
 
33
- impl<SG> RetryGateway<SG> {
34
- /// Use the provided retry config with the provided gateway
35
- pub const fn new(gateway: SG, retry_config: RetryConfig) -> Self {
37
+ impl<SG> RetryClient<SG> {
38
+ /// Use the provided retry config with the provided client
39
+ pub const fn new(client: SG, retry_config: RetryConfig) -> Self {
36
40
  Self {
37
- gateway,
41
+ client,
38
42
  retry_config,
39
43
  }
40
44
  }
41
45
  }
42
46
 
43
- impl<SG: ServerGatewayApis + Send + Sync + 'static> RetryGateway<SG> {
44
- async fn call_with_retry<R, F, Fut>(
47
+ impl<SG> RetryClient<SG> {
48
+ /// Return the inner client type
49
+ pub fn get_client(&self) -> &SG {
50
+ &self.client
51
+ }
52
+
53
+ /// Return the inner client type mutably
54
+ pub fn get_client_mut(&mut self) -> &mut SG {
55
+ &mut self.client
56
+ }
57
+
58
+ /// Disable retry and return the inner client type
59
+ pub fn into_inner(self) -> SG {
60
+ self.client
61
+ }
62
+
63
+ /// Wraps a call to the underlying client with retry capability.
64
+ ///
65
+ /// This is the "old" path used by higher-level [WorkflowClientTrait] implementors
66
+ pub(crate) async fn call_with_retry<R, F, Fut>(
45
67
  &self,
46
68
  factory: F,
47
- ct: CallType,
48
69
  call_name: &'static str,
49
70
  ) -> Result<R>
50
71
  where
51
72
  F: Fn() -> Fut + Unpin,
52
73
  Fut: Future<Output = Result<R>>,
53
74
  {
54
- let rtc = match ct {
75
+ let rtc = self.get_retry_config(call_name);
76
+ let res = Self::make_future_retry(rtc, factory, call_name).await;
77
+ Ok(res.map_err(|(e, _attempt)| e)?.0)
78
+ }
79
+
80
+ pub(crate) fn get_retry_config(&self, call_name: &'static str) -> RetryConfig {
81
+ let call_type = Self::determine_call_type(call_name);
82
+ match call_type {
55
83
  CallType::Normal => self.retry_config.clone(),
56
84
  CallType::LongPoll => RetryConfig::poll_retry_policy(),
57
- };
58
- Ok(
59
- FutureRetry::new(factory, TonicErrorHandler::new(rtc, ct, call_name))
60
- .await
61
- .map_err(|(e, _attempt)| e)?
62
- .0,
63
- )
85
+ }
86
+ }
87
+
88
+ pub(crate) fn make_future_retry<R, F, Fut>(
89
+ rtc: RetryConfig,
90
+ factory: F,
91
+ call_name: &'static str,
92
+ ) -> FutureRetry<F, TonicErrorHandler>
93
+ where
94
+ F: FnMut() -> Fut + Unpin,
95
+ Fut: Future<Output = Result<R>>,
96
+ {
97
+ let call_type = Self::determine_call_type(call_name);
98
+ FutureRetry::new(factory, TonicErrorHandler::new(rtc, call_type, call_name))
99
+ }
100
+
101
+ fn determine_call_type(call_name: &str) -> CallType {
102
+ match call_name {
103
+ "poll_workflow_task" | "poll_activity_task" => CallType::LongPoll,
104
+ _ => CallType::Normal,
105
+ }
64
106
  }
65
107
  }
66
108
 
67
109
  #[derive(Debug)]
68
- struct TonicErrorHandler {
110
+ pub(crate) struct TonicErrorHandler {
69
111
  backoff: ExponentialBackoff,
70
112
  max_retries: usize,
71
113
  call_type: CallType,
@@ -93,8 +135,9 @@ impl TonicErrorHandler {
93
135
  false
94
136
  }
95
137
  }
96
- #[derive(Debug, Eq, PartialEq, Hash)]
97
- enum CallType {
138
+ #[doc(hidden)]
139
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
140
+ pub enum CallType {
98
141
  Normal,
99
142
  LongPoll,
100
143
  }
@@ -139,31 +182,39 @@ impl ErrorHandler<tonic::Status> for TonicErrorHandler {
139
182
  }
140
183
 
141
184
  macro_rules! retry_call {
142
- ($myself:ident, $ctype:expr, $call_name:ident, $($args:expr),*) => {{
143
- let fact = move || { $myself.gateway.$call_name($($args,)*)};
144
- $myself.call_with_retry(fact, $ctype, stringify!($call_name)).await
145
- }};
185
+ ($myself:ident, $call_name:ident) => { retry_call!($myself, $call_name,) };
186
+ ($myself:ident, $call_name:ident, $($args:expr),*) => {{
187
+ let call_name_str = stringify!($call_name);
188
+ let fact = || { $myself.get_client().$call_name($($args,)*)};
189
+ $myself.call_with_retry(fact, call_name_str).await
190
+ }}
146
191
  }
147
192
 
193
+ // Ideally, this would be auto-implemented for anything that implements the raw client, but that
194
+ // breaks all our retry clients which use a mock since it's based on this trait currently. Ideally
195
+ // we would create an automock for the WorkflowServiceClient copy-paste trait and use that, but
196
+ // that's a huge pain. Maybe one day tonic will provide traits.
148
197
  #[async_trait::async_trait]
149
- impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryGateway<SG> {
198
+ impl<SG> WorkflowClientTrait for RetryClient<SG>
199
+ where
200
+ SG: WorkflowClientTrait + Send + Sync + 'static,
201
+ {
150
202
  async fn start_workflow(
151
203
  &self,
152
204
  input: Vec<Payload>,
153
205
  task_queue: String,
154
206
  workflow_id: String,
155
207
  workflow_type: String,
156
- task_timeout: Option<Duration>,
208
+ options: WorkflowOptions,
157
209
  ) -> Result<StartWorkflowExecutionResponse> {
158
210
  retry_call!(
159
211
  self,
160
- CallType::Normal,
161
212
  start_workflow,
162
213
  input.clone(),
163
214
  task_queue.clone(),
164
215
  workflow_id.clone(),
165
216
  workflow_type.clone(),
166
- task_timeout
217
+ options.clone()
167
218
  )
168
219
  }
169
220
 
@@ -172,24 +223,19 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
172
223
  task_queue: String,
173
224
  is_sticky: bool,
174
225
  ) -> Result<PollWorkflowTaskQueueResponse> {
175
- retry_call!(
176
- self,
177
- CallType::LongPoll,
178
- poll_workflow_task,
179
- task_queue.clone(),
180
- is_sticky
181
- )
226
+ retry_call!(self, poll_workflow_task, task_queue.clone(), is_sticky)
182
227
  }
183
228
 
184
229
  async fn poll_activity_task(
185
230
  &self,
186
231
  task_queue: String,
232
+ max_tasks_per_sec: Option<f64>,
187
233
  ) -> Result<PollActivityTaskQueueResponse> {
188
234
  retry_call!(
189
235
  self,
190
- CallType::LongPoll,
191
236
  poll_activity_task,
192
- task_queue.clone()
237
+ task_queue.clone(),
238
+ max_tasks_per_sec
193
239
  )
194
240
  }
195
241
 
@@ -200,7 +246,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
200
246
  ) -> Result<ResetStickyTaskQueueResponse> {
201
247
  retry_call!(
202
248
  self,
203
- CallType::Normal,
204
249
  reset_sticky_task_queue,
205
250
  workflow_id.clone(),
206
251
  run_id.clone()
@@ -211,12 +256,7 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
211
256
  &self,
212
257
  request: WorkflowTaskCompletion,
213
258
  ) -> Result<RespondWorkflowTaskCompletedResponse> {
214
- retry_call!(
215
- self,
216
- CallType::Normal,
217
- complete_workflow_task,
218
- request.clone()
219
- )
259
+ retry_call!(self, complete_workflow_task, request.clone())
220
260
  }
221
261
 
222
262
  async fn complete_activity_task(
@@ -226,7 +266,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
226
266
  ) -> Result<RespondActivityTaskCompletedResponse> {
227
267
  retry_call!(
228
268
  self,
229
- CallType::Normal,
230
269
  complete_activity_task,
231
270
  task_token.clone(),
232
271
  result.clone()
@@ -240,7 +279,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
240
279
  ) -> Result<RecordActivityTaskHeartbeatResponse> {
241
280
  retry_call!(
242
281
  self,
243
- CallType::Normal,
244
282
  record_activity_heartbeat,
245
283
  task_token.clone(),
246
284
  details.clone()
@@ -254,7 +292,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
254
292
  ) -> Result<RespondActivityTaskCanceledResponse> {
255
293
  retry_call!(
256
294
  self,
257
- CallType::Normal,
258
295
  cancel_activity_task,
259
296
  task_token.clone(),
260
297
  details.clone()
@@ -268,7 +305,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
268
305
  ) -> Result<RespondActivityTaskFailedResponse> {
269
306
  retry_call!(
270
307
  self,
271
- CallType::Normal,
272
308
  fail_activity_task,
273
309
  task_token.clone(),
274
310
  failure.clone()
@@ -283,7 +319,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
283
319
  ) -> Result<RespondWorkflowTaskFailedResponse> {
284
320
  retry_call!(
285
321
  self,
286
- CallType::Normal,
287
322
  fail_workflow_task,
288
323
  task_token.clone(),
289
324
  cause,
@@ -300,7 +335,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
300
335
  ) -> Result<SignalWorkflowExecutionResponse> {
301
336
  retry_call!(
302
337
  self,
303
- CallType::Normal,
304
338
  signal_workflow_execution,
305
339
  workflow_id.clone(),
306
340
  run_id.clone(),
@@ -317,7 +351,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
317
351
  ) -> Result<QueryWorkflowResponse> {
318
352
  retry_call!(
319
353
  self,
320
- CallType::Normal,
321
354
  query_workflow_execution,
322
355
  workflow_id.clone(),
323
356
  run_id.clone(),
@@ -332,7 +365,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
332
365
  ) -> Result<DescribeWorkflowExecutionResponse> {
333
366
  retry_call!(
334
367
  self,
335
- CallType::Normal,
336
368
  describe_workflow_execution,
337
369
  workflow_id.clone(),
338
370
  run_id.clone()
@@ -347,7 +379,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
347
379
  ) -> Result<GetWorkflowExecutionHistoryResponse> {
348
380
  retry_call!(
349
381
  self,
350
- CallType::Normal,
351
382
  get_workflow_execution_history,
352
383
  workflow_id.clone(),
353
384
  run_id.clone(),
@@ -362,7 +393,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
362
393
  ) -> Result<RespondQueryTaskCompletedResponse> {
363
394
  retry_call!(
364
395
  self,
365
- CallType::Normal,
366
396
  respond_legacy_query,
367
397
  task_token.clone(),
368
398
  query_result.clone()
@@ -376,7 +406,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
376
406
  ) -> Result<RequestCancelWorkflowExecutionResponse> {
377
407
  retry_call!(
378
408
  self,
379
- CallType::Normal,
380
409
  cancel_workflow_execution,
381
410
  workflow_id.clone(),
382
411
  run_id.clone()
@@ -390,7 +419,6 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
390
419
  ) -> Result<TerminateWorkflowExecutionResponse> {
391
420
  retry_call!(
392
421
  self,
393
- CallType::Normal,
394
422
  terminate_workflow_execution,
395
423
  workflow_id.clone(),
396
424
  run_id.clone()
@@ -398,18 +426,22 @@ impl<SG: ServerGatewayApis + Send + Sync + 'static> ServerGatewayApis for RetryG
398
426
  }
399
427
 
400
428
  async fn list_namespaces(&self) -> Result<ListNamespacesResponse> {
401
- retry_call!(self, CallType::Normal, list_namespaces,)
429
+ retry_call!(self, list_namespaces,)
402
430
  }
403
431
 
404
- fn get_options(&self) -> &ServerGatewayOptions {
405
- self.gateway.get_options()
432
+ fn get_options(&self) -> &ClientOptions {
433
+ self.client.get_options()
434
+ }
435
+
436
+ fn namespace(&self) -> &str {
437
+ self.client.namespace()
406
438
  }
407
439
  }
408
440
 
409
441
  #[cfg(test)]
410
442
  mod tests {
411
443
  use super::*;
412
- use crate::MockServerGatewayApis;
444
+ use crate::MockWorkflowClientTrait;
413
445
  use tonic::Status;
414
446
 
415
447
  #[tokio::test]
@@ -425,13 +457,13 @@ mod tests {
425
457
  Code::Unauthenticated,
426
458
  Code::Unimplemented,
427
459
  ] {
428
- let mut mock_gateway = MockServerGatewayApis::new();
429
- mock_gateway
460
+ let mut mock_client = MockWorkflowClientTrait::new();
461
+ mock_client
430
462
  .expect_cancel_activity_task()
431
463
  .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
432
464
  .times(1);
433
- let retry_gateway = RetryGateway::new(mock_gateway, Default::default());
434
- let result = retry_gateway
465
+ let retry_client = RetryClient::new(mock_client, Default::default());
466
+ let result = retry_client
435
467
  .cancel_activity_task(vec![1].into(), None)
436
468
  .await;
437
469
  // Expecting an error after a single attempt, since there was a non-retryable error.
@@ -450,21 +482,23 @@ mod tests {
450
482
  Code::Unauthenticated,
451
483
  Code::Unimplemented,
452
484
  ] {
453
- let mut mock_gateway = MockServerGatewayApis::new();
454
- mock_gateway
485
+ let mut mock_client = MockWorkflowClientTrait::new();
486
+ mock_client
455
487
  .expect_poll_workflow_task()
456
488
  .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
457
489
  .times(1);
458
- mock_gateway
490
+ mock_client
459
491
  .expect_poll_activity_task()
460
- .returning(move |_| Err(Status::new(code, "non-retryable failure")))
492
+ .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
461
493
  .times(1);
462
- let retry_gateway = RetryGateway::new(mock_gateway, Default::default());
463
- let result = retry_gateway
494
+ let retry_client = RetryClient::new(mock_client, Default::default());
495
+ let result = retry_client
464
496
  .poll_workflow_task("tq".to_string(), false)
465
497
  .await;
466
498
  assert!(result.is_err());
467
- let result = retry_gateway.poll_activity_task("tq".to_string()).await;
499
+ let result = retry_client
500
+ .poll_activity_task("tq".to_string(), None)
501
+ .await;
468
502
  assert!(result.is_err());
469
503
  }
470
504
  }
@@ -472,18 +506,18 @@ mod tests {
472
506
  #[tokio::test]
473
507
  async fn retryable_errors() {
474
508
  for code in RETRYABLE_ERROR_CODES {
475
- let mut mock_gateway = MockServerGatewayApis::new();
476
- mock_gateway
509
+ let mut mock_client = MockWorkflowClientTrait::new();
510
+ mock_client
477
511
  .expect_cancel_activity_task()
478
512
  .returning(move |_, _| Err(Status::new(code, "retryable failure")))
479
513
  .times(3);
480
- mock_gateway
514
+ mock_client
481
515
  .expect_cancel_activity_task()
482
516
  .returning(|_, _| Ok(Default::default()))
483
517
  .times(1);
484
518
 
485
- let retry_gateway = RetryGateway::new(mock_gateway, Default::default());
486
- let result = retry_gateway
519
+ let retry_client = RetryClient::new(mock_client, Default::default());
520
+ let result = retry_client
487
521
  .cancel_activity_task(vec![1].into(), None)
488
522
  .await;
489
523
  // Expecting successful response after retries
@@ -493,31 +527,33 @@ mod tests {
493
527
 
494
528
  #[tokio::test]
495
529
  async fn long_poll_retries_forever() {
496
- let mut mock_gateway = MockServerGatewayApis::new();
497
- mock_gateway
530
+ let mut mock_client = MockWorkflowClientTrait::new();
531
+ mock_client
498
532
  .expect_poll_workflow_task()
499
533
  .returning(move |_, _| Err(Status::new(Code::Unknown, "retryable failure")))
500
534
  .times(50);
501
- mock_gateway
535
+ mock_client
502
536
  .expect_poll_workflow_task()
503
537
  .returning(|_, _| Ok(Default::default()))
504
538
  .times(1);
505
- mock_gateway
539
+ mock_client
506
540
  .expect_poll_activity_task()
507
- .returning(move |_| Err(Status::new(Code::Unknown, "retryable failure")))
541
+ .returning(move |_, _| Err(Status::new(Code::Unknown, "retryable failure")))
508
542
  .times(50);
509
- mock_gateway
543
+ mock_client
510
544
  .expect_poll_activity_task()
511
- .returning(|_| Ok(Default::default()))
545
+ .returning(|_, _| Ok(Default::default()))
512
546
  .times(1);
513
547
 
514
- let retry_gateway = RetryGateway::new(mock_gateway, Default::default());
548
+ let retry_client = RetryClient::new(mock_client, Default::default());
515
549
 
516
- let result = retry_gateway
550
+ let result = retry_client
517
551
  .poll_workflow_task("tq".to_string(), false)
518
552
  .await;
519
553
  assert!(result.is_ok());
520
- let result = retry_gateway.poll_activity_task("tq".to_string()).await;
554
+ let result = retry_client
555
+ .poll_activity_task("tq".to_string(), None)
556
+ .await;
521
557
  assert!(result.is_ok());
522
558
  }
523
559
 
@@ -525,31 +561,33 @@ mod tests {
525
561
  async fn long_poll_retries_deadline_exceeded() {
526
562
  // For some reason we will get cancelled in these situations occasionally (always?) too
527
563
  for code in [Code::Cancelled, Code::DeadlineExceeded] {
528
- let mut mock_gateway = MockServerGatewayApis::new();
529
- mock_gateway
564
+ let mut mock_client = MockWorkflowClientTrait::new();
565
+ mock_client
530
566
  .expect_poll_workflow_task()
531
567
  .returning(move |_, _| Err(Status::new(code, "retryable failure")))
532
568
  .times(5);
533
- mock_gateway
569
+ mock_client
534
570
  .expect_poll_workflow_task()
535
571
  .returning(|_, _| Ok(Default::default()))
536
572
  .times(1);
537
- mock_gateway
573
+ mock_client
538
574
  .expect_poll_activity_task()
539
- .returning(move |_| Err(Status::new(code, "retryable failure")))
575
+ .returning(move |_, _| Err(Status::new(code, "retryable failure")))
540
576
  .times(5);
541
- mock_gateway
577
+ mock_client
542
578
  .expect_poll_activity_task()
543
- .returning(|_| Ok(Default::default()))
579
+ .returning(|_, _| Ok(Default::default()))
544
580
  .times(1);
545
581
 
546
- let retry_gateway = RetryGateway::new(mock_gateway, Default::default());
582
+ let retry_client = RetryClient::new(mock_client, Default::default());
547
583
 
548
- let result = retry_gateway
584
+ let result = retry_client
549
585
  .poll_workflow_task("tq".to_string(), false)
550
586
  .await;
551
587
  assert!(result.is_ok());
552
- let result = retry_gateway.poll_activity_task("tq".to_string()).await;
588
+ let result = retry_client
589
+ .poll_activity_task("tq".to_string(), None)
590
+ .await;
553
591
  assert!(result.is_ok());
554
592
  }
555
593
  }
@@ -19,7 +19,7 @@ async-trait = "0.1"
19
19
  base64 = "0.13"
20
20
  crossbeam = "0.8"
21
21
  dashmap = "5.0"
22
- derive_builder = "0.10"
22
+ derive_builder = "0.11"
23
23
  derive_more = "0.99"
24
24
  enum_dispatch = "0.3"
25
25
  futures = "0.3"
@@ -29,26 +29,28 @@ itertools = "0.10"
29
29
  lazy_static = "1.4"
30
30
  log = "0.4"
31
31
  lru = "0.7"
32
+ mockall = "0.11"
32
33
  once_cell = "1.5"
33
- opentelemetry = { version = "0.16", features = ["rt-tokio"] }
34
- opentelemetry-otlp = { version = "0.9.0", features = ["tokio", "metrics"] }
35
- opentelemetry-prometheus = "0.9.0"
36
- parking_lot = { version = "0.11", features = ["send_guard"] }
37
- prometheus = "0.12"
34
+ opentelemetry = { version = "0.17", features = ["rt-tokio"] }
35
+ opentelemetry-otlp = { version = "0.10.0", features = ["tokio", "metrics"] }
36
+ opentelemetry-prometheus = "0.10.0"
37
+ parking_lot = { version = "0.12", features = ["send_guard"] }
38
+ prometheus = "0.13"
38
39
  prost = "0.9"
39
40
  prost-types = "0.9"
40
41
  rand = "0.8.3"
41
42
  ringbuf = "0.2"
42
43
  serde = "1.0"
44
+ siphasher = "0.3"
43
45
  slotmap = "1.0"
44
46
  thiserror = "1.0"
45
47
  tokio = { version = "1.1", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
46
- tokio-util = { version = "0.6.9" }
48
+ tokio-util = { version = "0.7" }
47
49
  tokio-stream = "0.1"
48
50
  tonic = { version = "0.6", features = ["tls", "tls-roots"] }
49
51
  tracing = { version = "0.1", features = ["log-always"] }
50
52
  tracing-futures = "0.2"
51
- tracing-opentelemetry = "0.16"
53
+ tracing-opentelemetry = "0.17"
52
54
  tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter"] }
53
55
  url = "2.2"
54
56
  uuid = { version = "0.8.2", features = ["v4"] }
@@ -66,7 +68,6 @@ features = ["history_builders"]
66
68
  [dependencies.temporal-client]
67
69
  path = "../client"
68
70
  version = "0.1"
69
- features = ["mocks"]
70
71
 
71
72
  [dependencies.rustfsm]
72
73
  path = "../fsm"
@@ -75,7 +76,7 @@ version = "0.1"
75
76
  [dev-dependencies]
76
77
  assert_matches = "1.4"
77
78
  bimap = "0.6.1"
78
- mockall = "0.11"
79
+ criterion = "0.3"
79
80
  rstest = "0.12"
80
81
  temporal-sdk-core-test-utils = { path = "../test-utils" }
81
82
  temporal-sdk = { path = "../sdk" }
@@ -94,3 +95,7 @@ test = false
94
95
  name = "load_tests"
95
96
  path = "../tests/load_tests.rs"
96
97
  test = false
98
+
99
+ [[bench]]
100
+ name = "workflow_replay"
101
+ harness = false
@@ -0,0 +1,23 @@
1
+ Temporal Core SDK
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2021 Temporal Technologies, Inc. All Rights Reserved
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,79 @@
1
+ use criterion::{criterion_group, criterion_main, Criterion};
2
+ use futures::StreamExt;
3
+ use std::time::Duration;
4
+ use temporal_sdk::{WfContext, Worker, WorkflowFunction};
5
+ use temporal_sdk_core::{telemetry_init, TelemetryOptionsBuilder};
6
+ use temporal_sdk_core_protos::DEFAULT_WORKFLOW_TYPE;
7
+ use temporal_sdk_core_test_utils::{canned_histories, init_core_replay_preloaded};
8
+
9
+ pub fn criterion_benchmark(c: &mut Criterion) {
10
+ let tokio_runtime = tokio::runtime::Builder::new_current_thread()
11
+ .enable_time()
12
+ .build()
13
+ .unwrap();
14
+ telemetry_init(
15
+ &TelemetryOptionsBuilder::default()
16
+ .totally_disable(true)
17
+ .build()
18
+ .unwrap(),
19
+ )
20
+ .unwrap();
21
+ let _g = tokio_runtime.enter();
22
+
23
+ let num_timers = 10;
24
+ let t = canned_histories::long_sequential_timers(num_timers as usize);
25
+ let hist = t.get_full_history_info().unwrap().into();
26
+
27
+ c.bench_function("Small history replay", |b| {
28
+ b.iter(|| {
29
+ tokio_runtime.block_on(async {
30
+ let func = timers_wf(num_timers);
31
+ let (worker, _) = init_core_replay_preloaded("replay_bench", &hist);
32
+ let mut worker = Worker::new_from_core(worker, "replay_bench".to_string());
33
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
34
+ worker.run().await.unwrap();
35
+ })
36
+ })
37
+ });
38
+
39
+ let num_tasks = 50;
40
+ let t = canned_histories::lots_of_big_signals(num_tasks);
41
+ let hist = t.get_full_history_info().unwrap().into();
42
+
43
+ c.bench_function("Large payloads history replay", |b| {
44
+ b.iter(|| {
45
+ tokio_runtime.block_on(async {
46
+ let func = big_signals_wf(num_tasks);
47
+ let (worker, _) = init_core_replay_preloaded("large_hist_bench", &hist);
48
+ let mut worker = Worker::new_from_core(worker, "large_hist_bench".to_string());
49
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
50
+ worker.run().await.unwrap();
51
+ })
52
+ })
53
+ });
54
+ }
55
+
56
+ criterion_group!(benches, criterion_benchmark);
57
+ criterion_main!(benches);
58
+
59
+ fn timers_wf(num_timers: u32) -> WorkflowFunction {
60
+ WorkflowFunction::new(move |ctx: WfContext| async move {
61
+ for _ in 1..=num_timers {
62
+ ctx.timer(Duration::from_secs(1)).await;
63
+ }
64
+ Ok(().into())
65
+ })
66
+ }
67
+
68
+ fn big_signals_wf(num_tasks: usize) -> WorkflowFunction {
69
+ WorkflowFunction::new(move |ctx: WfContext| async move {
70
+ let mut sigs = ctx.make_signal_channel("bigsig");
71
+ for _ in 1..=num_tasks {
72
+ for _ in 1..=5 {
73
+ let _ = sigs.next().await.unwrap();
74
+ }
75
+ }
76
+
77
+ Ok(().into())
78
+ })
79
+ }