@temporalio/core-bridge 1.1.0 → 1.3.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 (114) hide show
  1. package/Cargo.lock +786 -54
  2. package/Cargo.toml +2 -2
  3. package/common.js +7 -3
  4. package/index.d.ts +110 -3
  5. package/index.js +2 -6
  6. package/package.json +3 -3
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/releases/x86_64-apple-darwin/index.node +0 -0
  10. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  11. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  12. package/scripts/build.js +4 -3
  13. package/sdk-core/.buildkite/docker/Dockerfile +2 -1
  14. package/sdk-core/ARCHITECTURE.md +2 -2
  15. package/sdk-core/README.md +12 -0
  16. package/sdk-core/bridge-ffi/Cargo.toml +2 -2
  17. package/sdk-core/client/Cargo.toml +6 -4
  18. package/sdk-core/client/src/lib.rs +338 -215
  19. package/sdk-core/client/src/raw.rs +352 -106
  20. package/sdk-core/client/src/retry.rs +159 -133
  21. package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
  22. package/sdk-core/core/Cargo.toml +18 -9
  23. package/sdk-core/core/src/core_tests/activity_tasks.rs +63 -23
  24. package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
  25. package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
  26. package/sdk-core/core/src/core_tests/workers.rs +3 -2
  27. package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
  28. package/sdk-core/core/src/ephemeral_server/mod.rs +499 -0
  29. package/sdk-core/core/src/lib.rs +60 -26
  30. package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
  31. package/sdk-core/core/src/replay/mod.rs +3 -3
  32. package/sdk-core/core/src/retry_logic.rs +10 -9
  33. package/sdk-core/core/src/telemetry/mod.rs +10 -7
  34. package/sdk-core/core/src/test_help/mod.rs +18 -8
  35. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
  36. package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
  37. package/sdk-core/core/src/worker/activities.rs +6 -12
  38. package/sdk-core/core/src/worker/client.rs +193 -64
  39. package/sdk-core/core/src/worker/mod.rs +14 -19
  40. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
  41. package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
  42. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
  43. package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
  44. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
  45. package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
  46. package/sdk-core/core/src/worker/workflow/mod.rs +59 -58
  47. package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
  48. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
  49. package/sdk-core/core-api/Cargo.toml +2 -2
  50. package/sdk-core/core-api/src/errors.rs +3 -11
  51. package/sdk-core/core-api/src/worker.rs +7 -0
  52. package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
  53. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
  54. package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
  55. package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
  56. package/sdk-core/protos/api_upstream/Makefile +2 -2
  57. package/sdk-core/protos/api_upstream/buf.yaml +1 -0
  58. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
  59. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
  60. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
  61. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
  62. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
  63. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
  64. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
  65. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
  66. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
  67. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
  68. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
  69. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
  70. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
  71. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
  73. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
  74. package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  75. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
  76. package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
  77. package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  78. package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  79. package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  80. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  81. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  82. package/sdk-core/sdk/Cargo.toml +2 -2
  83. package/sdk-core/sdk/src/lib.rs +2 -2
  84. package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
  85. package/sdk-core/sdk/src/workflow_context.rs +30 -6
  86. package/sdk-core/sdk/src/workflow_future.rs +4 -4
  87. package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
  88. package/sdk-core/sdk-core-protos/build.rs +9 -1
  89. package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
  90. package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
  91. package/sdk-core/test-utils/Cargo.toml +3 -3
  92. package/sdk-core/test-utils/src/canned_histories.rs +58 -0
  93. package/sdk-core/test-utils/src/lib.rs +14 -10
  94. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +141 -0
  95. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
  96. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
  97. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  98. package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  99. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
  100. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  101. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
  102. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +1 -1
  103. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
  104. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
  105. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
  106. package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
  107. package/sdk-core/tests/load_tests.rs +2 -1
  108. package/sdk-core/tests/main.rs +10 -0
  109. package/src/conversions.rs +138 -91
  110. package/src/helpers.rs +190 -0
  111. package/src/lib.rs +10 -912
  112. package/src/runtime.rs +436 -0
  113. package/src/testing.rs +67 -0
  114. package/src/worker.rs +465 -0
@@ -1,14 +1,14 @@
1
1
  use crate::{
2
- ClientOptions, RawClientLikeUser, Result, RetryConfig, WorkflowClientTrait, WorkflowOptions,
3
- WorkflowTaskCompletion,
2
+ ClientOptions, ListClosedFilters, ListOpenFilters, Namespace, Result, RetryConfig,
3
+ StartTimeFilter, WorkflowClientTrait, WorkflowOptions,
4
4
  };
5
- use backoff::{backoff::Backoff, ExponentialBackoff};
5
+ use backoff::{backoff::Backoff, exponential::ExponentialBackoff, Clock, SystemClock};
6
6
  use futures_retry::{ErrorHandler, FutureRetry, RetryPolicy};
7
- use std::{fmt::Debug, future::Future, time::Duration};
7
+ use std::{fmt::Debug, future::Future, sync::Arc, time::Duration};
8
8
  use temporal_sdk_core_protos::{
9
9
  coresdk::workflow_commands::QueryResult,
10
10
  temporal::api::{
11
- common::v1::{Payload, Payloads},
11
+ common::v1::{Header, Payload, Payloads},
12
12
  enums::v1::WorkflowTaskFailedCause,
13
13
  failure::v1::Failure,
14
14
  query::v1::WorkflowQuery,
@@ -28,21 +28,22 @@ pub const RETRYABLE_ERROR_CODES: [Code; 7] = [
28
28
  Code::OutOfRange,
29
29
  Code::Unavailable,
30
30
  ];
31
+ const LONG_POLL_FATAL_GRACE: Duration = Duration::from_secs(60);
31
32
 
32
33
  /// A wrapper for a [WorkflowClientTrait] or [crate::WorkflowService] implementor which performs
33
34
  /// auto-retries
34
35
  #[derive(Debug, Clone)]
35
36
  pub struct RetryClient<SG> {
36
37
  client: SG,
37
- retry_config: RetryConfig,
38
+ retry_config: Arc<RetryConfig>,
38
39
  }
39
40
 
40
41
  impl<SG> RetryClient<SG> {
41
42
  /// Use the provided retry config with the provided client
42
- pub const fn new(client: SG, retry_config: RetryConfig) -> Self {
43
+ pub fn new(client: SG, retry_config: RetryConfig) -> Self {
43
44
  Self {
44
45
  client,
45
- retry_config,
46
+ retry_config: Arc::new(retry_config),
46
47
  }
47
48
  }
48
49
  }
@@ -83,7 +84,7 @@ impl<SG> RetryClient<SG> {
83
84
  pub(crate) fn get_retry_config(&self, call_name: &'static str) -> RetryConfig {
84
85
  let call_type = Self::determine_call_type(call_name);
85
86
  match call_type {
86
- CallType::Normal => self.retry_config.clone(),
87
+ CallType::Normal => (*self.retry_config).clone(),
87
88
  CallType::LongPoll => RetryConfig::poll_retry_policy(),
88
89
  }
89
90
  }
@@ -92,7 +93,7 @@ impl<SG> RetryClient<SG> {
92
93
  rtc: RetryConfig,
93
94
  factory: F,
94
95
  call_name: &'static str,
95
- ) -> FutureRetry<F, TonicErrorHandler>
96
+ ) -> FutureRetry<F, TonicErrorHandler<SystemClock>>
96
97
  where
97
98
  F: FnMut() -> Fut + Unpin,
98
99
  Fut: Future<Output = Result<R>>,
@@ -110,13 +111,13 @@ impl<SG> RetryClient<SG> {
110
111
  }
111
112
 
112
113
  #[derive(Debug)]
113
- pub(crate) struct TonicErrorHandler {
114
- backoff: ExponentialBackoff,
114
+ pub(crate) struct TonicErrorHandler<C: Clock> {
115
+ backoff: ExponentialBackoff<C>,
115
116
  max_retries: usize,
116
117
  call_type: CallType,
117
118
  call_name: &'static str,
118
119
  }
119
- impl TonicErrorHandler {
120
+ impl TonicErrorHandler<SystemClock> {
120
121
  fn new(cfg: RetryConfig, call_type: CallType, call_name: &'static str) -> Self {
121
122
  Self {
122
123
  max_retries: cfg.max_retries,
@@ -125,7 +126,11 @@ impl TonicErrorHandler {
125
126
  backoff: cfg.into(),
126
127
  }
127
128
  }
128
-
129
+ }
130
+ impl<C> TonicErrorHandler<C>
131
+ where
132
+ C: Clock,
133
+ {
129
134
  const fn should_log_retry_warning(&self, cur_attempt: usize) -> bool {
130
135
  // Warn on more than 5 retries for unlimited retrying
131
136
  if self.max_retries == 0 && cur_attempt > 5 {
@@ -145,7 +150,10 @@ pub enum CallType {
145
150
  LongPoll,
146
151
  }
147
152
 
148
- impl ErrorHandler<tonic::Status> for TonicErrorHandler {
153
+ impl<C> ErrorHandler<tonic::Status> for TonicErrorHandler<C>
154
+ where
155
+ C: Clock,
156
+ {
149
157
  type OutError = tonic::Status;
150
158
 
151
159
  fn handle(&mut self, current_attempt: usize, e: tonic::Status) -> RetryPolicy<tonic::Status> {
@@ -154,10 +162,11 @@ impl ErrorHandler<tonic::Status> for TonicErrorHandler {
154
162
  return RetryPolicy::ForwardError(e);
155
163
  }
156
164
 
165
+ let is_long_poll = self.call_type == CallType::LongPoll;
157
166
  // Long polls are OK with being cancelled or running into the timeout because there's
158
167
  // nothing to do but retry anyway
159
- let long_poll_allowed = self.call_type == CallType::LongPoll
160
- && [Code::Cancelled, Code::DeadlineExceeded].contains(&e.code());
168
+ let long_poll_allowed =
169
+ is_long_poll && [Code::Cancelled, Code::DeadlineExceeded].contains(&e.code());
161
170
 
162
171
  if RETRYABLE_ERROR_CODES.contains(&e.code()) || long_poll_allowed {
163
172
  if current_attempt == 1 {
@@ -178,6 +187,10 @@ impl ErrorHandler<tonic::Status> for TonicErrorHandler {
178
187
  }
179
188
  }
180
189
  }
190
+ } else if is_long_poll && self.backoff.get_elapsed_time() <= LONG_POLL_FATAL_GRACE {
191
+ // We permit "fatal" errors while long polling for a while, because some proxies return
192
+ // stupid error codes while getting ready, among other weird infra issues
193
+ RetryPolicy::WaitRetry(self.backoff.max_interval)
181
194
  } else {
182
195
  RetryPolicy::ForwardError(e)
183
196
  }
@@ -208,6 +221,7 @@ where
208
221
  task_queue: String,
209
222
  workflow_id: String,
210
223
  workflow_type: String,
224
+ request_id: Option<String>,
211
225
  options: WorkflowOptions,
212
226
  ) -> Result<StartWorkflowExecutionResponse> {
213
227
  retry_call!(
@@ -217,31 +231,11 @@ where
217
231
  task_queue.clone(),
218
232
  workflow_id.clone(),
219
233
  workflow_type.clone(),
234
+ request_id.clone(),
220
235
  options.clone()
221
236
  )
222
237
  }
223
238
 
224
- async fn poll_workflow_task(
225
- &self,
226
- task_queue: String,
227
- is_sticky: bool,
228
- ) -> Result<PollWorkflowTaskQueueResponse> {
229
- retry_call!(self, poll_workflow_task, task_queue.clone(), is_sticky)
230
- }
231
-
232
- async fn poll_activity_task(
233
- &self,
234
- task_queue: String,
235
- max_tasks_per_sec: Option<f64>,
236
- ) -> Result<PollActivityTaskQueueResponse> {
237
- retry_call!(
238
- self,
239
- poll_activity_task,
240
- task_queue.clone(),
241
- max_tasks_per_sec
242
- )
243
- }
244
-
245
239
  async fn reset_sticky_task_queue(
246
240
  &self,
247
241
  workflow_id: String,
@@ -255,13 +249,6 @@ where
255
249
  )
256
250
  }
257
251
 
258
- async fn complete_workflow_task(
259
- &self,
260
- request: WorkflowTaskCompletion,
261
- ) -> Result<RespondWorkflowTaskCompletedResponse> {
262
- retry_call!(self, complete_workflow_task, request.clone())
263
- }
264
-
265
252
  async fn complete_activity_task(
266
253
  &self,
267
254
  task_token: TaskToken,
@@ -335,6 +322,7 @@ where
335
322
  run_id: String,
336
323
  signal_name: String,
337
324
  payloads: Option<Payloads>,
325
+ request_id: Option<String>,
338
326
  ) -> Result<SignalWorkflowExecutionResponse> {
339
327
  retry_call!(
340
328
  self,
@@ -342,7 +330,8 @@ where
342
330
  workflow_id.clone(),
343
331
  run_id.clone(),
344
332
  signal_name.clone(),
345
- payloads.clone()
333
+ payloads.clone(),
334
+ request_id.clone()
346
335
  )
347
336
  }
348
337
 
@@ -352,9 +341,11 @@ where
352
341
  task_queue: String,
353
342
  workflow_id: String,
354
343
  workflow_type: String,
344
+ request_id: Option<String>,
355
345
  options: WorkflowOptions,
356
346
  signal_name: String,
357
347
  signal_input: Option<Payloads>,
348
+ signal_header: Option<Header>,
358
349
  ) -> Result<SignalWithStartWorkflowExecutionResponse> {
359
350
  retry_call!(
360
351
  self,
@@ -363,9 +354,11 @@ where
363
354
  task_queue.clone(),
364
355
  workflow_id.clone(),
365
356
  workflow_type.clone(),
357
+ request_id.clone(),
366
358
  options.clone(),
367
359
  signal_name.clone(),
368
- signal_input.clone()
360
+ signal_input.clone(),
361
+ signal_header.clone()
369
362
  )
370
363
  }
371
364
 
@@ -430,13 +423,15 @@ where
430
423
  workflow_id: String,
431
424
  run_id: Option<String>,
432
425
  reason: String,
426
+ request_id: Option<String>,
433
427
  ) -> Result<RequestCancelWorkflowExecutionResponse> {
434
428
  retry_call!(
435
429
  self,
436
430
  cancel_workflow_execution,
437
431
  workflow_id.clone(),
438
432
  run_id.clone(),
439
- reason.clone()
433
+ reason.clone(),
434
+ request_id.clone()
440
435
  )
441
436
  }
442
437
 
@@ -457,6 +452,59 @@ where
457
452
  retry_call!(self, list_namespaces,)
458
453
  }
459
454
 
455
+ async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
456
+ retry_call!(self, describe_namespace, namespace.clone())
457
+ }
458
+
459
+ async fn list_open_workflow_executions(
460
+ &self,
461
+ maximum_page_size: i32,
462
+ next_page_token: Vec<u8>,
463
+ start_time_filter: Option<StartTimeFilter>,
464
+ filters: Option<ListOpenFilters>,
465
+ ) -> Result<ListOpenWorkflowExecutionsResponse> {
466
+ retry_call!(
467
+ self,
468
+ list_open_workflow_executions,
469
+ maximum_page_size,
470
+ next_page_token.clone(),
471
+ start_time_filter.clone(),
472
+ filters.clone()
473
+ )
474
+ }
475
+
476
+ async fn list_closed_workflow_executions(
477
+ &self,
478
+ maximum_page_size: i32,
479
+ next_page_token: Vec<u8>,
480
+ start_time_filter: Option<StartTimeFilter>,
481
+ filters: Option<ListClosedFilters>,
482
+ ) -> Result<ListClosedWorkflowExecutionsResponse> {
483
+ retry_call!(
484
+ self,
485
+ list_closed_workflow_executions,
486
+ maximum_page_size,
487
+ next_page_token.clone(),
488
+ start_time_filter.clone(),
489
+ filters.clone()
490
+ )
491
+ }
492
+
493
+ async fn list_workflow_executions(
494
+ &self,
495
+ page_size: i32,
496
+ next_page_token: Vec<u8>,
497
+ query: String,
498
+ ) -> Result<ListWorkflowExecutionsResponse> {
499
+ retry_call!(
500
+ self,
501
+ list_workflow_executions,
502
+ page_size,
503
+ next_page_token.clone(),
504
+ query.clone()
505
+ )
506
+ }
507
+
460
508
  fn get_options(&self) -> &ClientOptions {
461
509
  self.client.get_options()
462
510
  }
@@ -466,21 +514,13 @@ where
466
514
  }
467
515
  }
468
516
 
469
- impl<C> RawClientLikeUser for RetryClient<C>
470
- where
471
- C: RawClientLikeUser,
472
- {
473
- type RawClientT = C::RawClientT;
474
-
475
- fn wf_svc(&self) -> Self::RawClientT {
476
- self.client.wf_svc()
477
- }
478
- }
479
-
480
517
  #[cfg(test)]
481
518
  mod tests {
482
519
  use super::*;
483
520
  use crate::MockWorkflowClientTrait;
521
+ use assert_matches::assert_matches;
522
+ use backoff::Clock;
523
+ use std::{ops::Add, time::Instant};
484
524
  use tonic::Status;
485
525
 
486
526
  #[tokio::test]
@@ -510,6 +550,13 @@ mod tests {
510
550
  }
511
551
  }
512
552
 
553
+ struct FixedClock(Instant);
554
+ impl Clock for FixedClock {
555
+ fn now(&self) -> Instant {
556
+ self.0
557
+ }
558
+ }
559
+
513
560
  #[tokio::test]
514
561
  async fn long_poll_non_retryable_errors() {
515
562
  for code in [
@@ -521,24 +568,33 @@ mod tests {
521
568
  Code::Unauthenticated,
522
569
  Code::Unimplemented,
523
570
  ] {
524
- let mut mock_client = MockWorkflowClientTrait::new();
525
- mock_client
526
- .expect_poll_workflow_task()
527
- .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
528
- .times(1);
529
- mock_client
530
- .expect_poll_activity_task()
531
- .returning(move |_, _| Err(Status::new(code, "non-retryable failure")))
532
- .times(1);
533
- let retry_client = RetryClient::new(mock_client, Default::default());
534
- let result = retry_client
535
- .poll_workflow_task("tq".to_string(), false)
536
- .await;
537
- assert!(result.is_err());
538
- let result = retry_client
539
- .poll_activity_task("tq".to_string(), None)
540
- .await;
541
- assert!(result.is_err());
571
+ for call_name in ["poll_workflow_task", "poll_activity_task"] {
572
+ let retry_cfg = RetryConfig::default();
573
+ let mut err_handler = TonicErrorHandler {
574
+ max_retries: retry_cfg.max_retries,
575
+ call_type: CallType::LongPoll,
576
+ call_name,
577
+ backoff: ExponentialBackoff {
578
+ current_interval: retry_cfg.initial_interval,
579
+ initial_interval: retry_cfg.initial_interval,
580
+ randomization_factor: retry_cfg.randomization_factor,
581
+ multiplier: retry_cfg.multiplier,
582
+ max_interval: retry_cfg.max_interval,
583
+ max_elapsed_time: retry_cfg.max_elapsed_time,
584
+ clock: FixedClock(Instant::now()),
585
+ start_time: Instant::now(),
586
+ },
587
+ };
588
+ let result = err_handler.handle(1, Status::new(code, "Ahh"));
589
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
590
+ err_handler.backoff.clock.0 = err_handler
591
+ .backoff
592
+ .clock
593
+ .0
594
+ .add(LONG_POLL_FATAL_GRACE + Duration::from_secs(1));
595
+ let result = err_handler.handle(2, Status::new(code, "Ahh"));
596
+ assert_matches!(result, RetryPolicy::ForwardError(_));
597
+ }
542
598
  }
543
599
  }
544
600
 
@@ -566,68 +622,38 @@ mod tests {
566
622
 
567
623
  #[tokio::test]
568
624
  async fn long_poll_retries_forever() {
569
- let mut mock_client = MockWorkflowClientTrait::new();
570
- mock_client
571
- .expect_poll_workflow_task()
572
- .returning(move |_, _| Err(Status::new(Code::Unknown, "retryable failure")))
573
- .times(50);
574
- mock_client
575
- .expect_poll_workflow_task()
576
- .returning(|_, _| Ok(Default::default()))
577
- .times(1);
578
- mock_client
579
- .expect_poll_activity_task()
580
- .returning(move |_, _| Err(Status::new(Code::Unknown, "retryable failure")))
581
- .times(50);
582
- mock_client
583
- .expect_poll_activity_task()
584
- .returning(|_, _| Ok(Default::default()))
585
- .times(1);
586
-
587
- let retry_client = RetryClient::new(mock_client, Default::default());
588
-
589
- let result = retry_client
590
- .poll_workflow_task("tq".to_string(), false)
591
- .await;
592
- assert!(result.is_ok());
593
- let result = retry_client
594
- .poll_activity_task("tq".to_string(), None)
595
- .await;
596
- assert!(result.is_ok());
625
+ // A bit odd, but we don't need a real client to test the retry client passes through the
626
+ // correct retry config
627
+ let fake_retry = RetryClient::new((), Default::default());
628
+ for i in 1..=50 {
629
+ for call in ["poll_workflow_task", "poll_activity_task"] {
630
+ let mut err_handler = TonicErrorHandler::new(
631
+ fake_retry.get_retry_config(call),
632
+ CallType::LongPoll,
633
+ call,
634
+ );
635
+ let result = err_handler.handle(i, Status::new(Code::Unknown, "Ahh"));
636
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
637
+ }
638
+ }
597
639
  }
598
640
 
599
641
  #[tokio::test]
600
642
  async fn long_poll_retries_deadline_exceeded() {
643
+ let fake_retry = RetryClient::new((), Default::default());
601
644
  // For some reason we will get cancelled in these situations occasionally (always?) too
602
645
  for code in [Code::Cancelled, Code::DeadlineExceeded] {
603
- let mut mock_client = MockWorkflowClientTrait::new();
604
- mock_client
605
- .expect_poll_workflow_task()
606
- .returning(move |_, _| Err(Status::new(code, "retryable failure")))
607
- .times(5);
608
- mock_client
609
- .expect_poll_workflow_task()
610
- .returning(|_, _| Ok(Default::default()))
611
- .times(1);
612
- mock_client
613
- .expect_poll_activity_task()
614
- .returning(move |_, _| Err(Status::new(code, "retryable failure")))
615
- .times(5);
616
- mock_client
617
- .expect_poll_activity_task()
618
- .returning(|_, _| Ok(Default::default()))
619
- .times(1);
620
-
621
- let retry_client = RetryClient::new(mock_client, Default::default());
622
-
623
- let result = retry_client
624
- .poll_workflow_task("tq".to_string(), false)
625
- .await;
626
- assert!(result.is_ok());
627
- let result = retry_client
628
- .poll_activity_task("tq".to_string(), None)
629
- .await;
630
- assert!(result.is_ok());
646
+ for call in ["poll_workflow_task", "poll_activity_task"] {
647
+ let mut err_handler = TonicErrorHandler::new(
648
+ fake_retry.get_retry_config(call),
649
+ CallType::LongPoll,
650
+ call,
651
+ );
652
+ for i in 1..=5 {
653
+ let result = err_handler.handle(i, Status::new(code, "retryable failure"));
654
+ assert_matches!(result, RetryPolicy::WaitRetry(_));
655
+ }
656
+ }
631
657
  }
632
658
  }
633
659
  }
@@ -100,7 +100,7 @@ where
100
100
  let server_res = self
101
101
  .client
102
102
  .clone()
103
- .client()
103
+ .workflow_client()
104
104
  .get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
105
105
  namespace: self.info.namespace.to_string(),
106
106
  execution: Some(WorkflowExecution {
@@ -23,39 +23,48 @@ dashmap = "5.0"
23
23
  derive_builder = "0.11"
24
24
  derive_more = "0.99"
25
25
  enum_dispatch = "0.3"
26
+ flate2 = "1.0"
26
27
  futures = "0.3"
28
+ futures-util = "0.3"
27
29
  governor = "0.4"
28
30
  http = "0.2"
29
31
  hyper = "0.14"
30
32
  itertools = "0.10"
31
33
  lazy_static = "1.4"
32
34
  log = "0.4"
33
- lru = "0.7"
35
+ lru = "0.8"
34
36
  mockall = "0.11"
37
+ nix = "0.25"
35
38
  once_cell = "1.5"
36
39
  opentelemetry = { version = "0.17", features = ["rt-tokio"] }
37
40
  opentelemetry-otlp = { version = "0.10.0", features = ["tokio", "metrics"] }
38
41
  opentelemetry-prometheus = "0.10.0"
39
42
  parking_lot = { version = "0.12", features = ["send_guard"] }
40
43
  prometheus = "0.13"
41
- prost = "0.9"
42
- prost-types = "0.9"
44
+ prost = "0.11"
45
+ prost-types = "0.11"
43
46
  rand = "0.8.3"
47
+ reqwest = { version = "0.11", features = ["json", "stream", "rustls-tls", "tokio-rustls"], default-features = false }
44
48
  ringbuf = "0.2"
45
49
  serde = "1.0"
50
+ serde_json = "1.0"
46
51
  siphasher = "0.3"
47
52
  slotmap = "1.0"
53
+ tar = "0.4"
48
54
  thiserror = "1.0"
49
- tokio = { version = "1.1", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs"] }
50
- tokio-util = { version = "0.7" }
55
+ tokio = { version = "1.1", features = ["rt", "rt-multi-thread", "parking_lot", "time", "fs", "process"] }
56
+ tokio-util = { version = "0.7", features = ["io", "io-util"] }
51
57
  tokio-stream = "0.1"
52
- tonic = { version = "0.6", features = ["tls", "tls-roots"] }
58
+ tonic = { version = "0.8", features = ["tls", "tls-roots"] }
59
+ # TODO: Get rid of this once otel updates its tonic dep
60
+ tonic_otel = { version = "0.6", package = "tonic" }
53
61
  tracing = { version = "0.1", features = ["log-always"] }
54
62
  tracing-futures = "0.2"
55
63
  tracing-opentelemetry = "0.17"
56
64
  tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter"] }
57
65
  url = "2.2"
58
- uuid = { version = "0.8.2", features = ["v4"] }
66
+ uuid = { version = "1.1", features = ["v4"] }
67
+ zip = "0.6"
59
68
 
60
69
  # 1st party local deps
61
70
  [dependencies.temporal-sdk-core-api]
@@ -79,12 +88,12 @@ version = "0.1"
79
88
  assert_matches = "1.4"
80
89
  bimap = "0.6.1"
81
90
  criterion = "0.3"
82
- rstest = "0.12"
91
+ rstest = "0.15"
83
92
  temporal-sdk-core-test-utils = { path = "../test-utils" }
84
93
  temporal-sdk = { path = "../sdk" }
85
94
 
86
95
  [build-dependencies]
87
- tonic-build = "0.6"
96
+ tonic-build = "0.8"
88
97
 
89
98
  [[test]]
90
99
  name = "integ_tests"