@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.
- package/Cargo.lock +786 -54
- package/Cargo.toml +2 -2
- package/common.js +7 -3
- package/index.d.ts +110 -3
- package/index.js +2 -6
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/scripts/build.js +4 -3
- package/sdk-core/.buildkite/docker/Dockerfile +2 -1
- package/sdk-core/ARCHITECTURE.md +2 -2
- package/sdk-core/README.md +12 -0
- package/sdk-core/bridge-ffi/Cargo.toml +2 -2
- package/sdk-core/client/Cargo.toml +6 -4
- package/sdk-core/client/src/lib.rs +338 -215
- package/sdk-core/client/src/raw.rs +352 -106
- package/sdk-core/client/src/retry.rs +159 -133
- package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
- package/sdk-core/core/Cargo.toml +18 -9
- package/sdk-core/core/src/core_tests/activity_tasks.rs +63 -23
- package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
- package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
- package/sdk-core/core/src/core_tests/workers.rs +3 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
- package/sdk-core/core/src/ephemeral_server/mod.rs +499 -0
- package/sdk-core/core/src/lib.rs +60 -26
- package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
- package/sdk-core/core/src/replay/mod.rs +3 -3
- package/sdk-core/core/src/retry_logic.rs +10 -9
- package/sdk-core/core/src/telemetry/mod.rs +10 -7
- package/sdk-core/core/src/test_help/mod.rs +18 -8
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
- package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
- package/sdk-core/core/src/worker/activities.rs +6 -12
- package/sdk-core/core/src/worker/client.rs +193 -64
- package/sdk-core/core/src/worker/mod.rs +14 -19
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
- package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
- package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
- package/sdk-core/core/src/worker/workflow/mod.rs +59 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
- package/sdk-core/core-api/Cargo.toml +2 -2
- package/sdk-core/core-api/src/errors.rs +3 -11
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
- package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
- package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
- package/sdk-core/protos/api_upstream/Makefile +2 -2
- package/sdk-core/protos/api_upstream/buf.yaml +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
- package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
- package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
- package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
- package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +2 -2
- package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
- package/sdk-core/sdk/src/workflow_context.rs +30 -6
- package/sdk-core/sdk/src/workflow_future.rs +4 -4
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
- package/sdk-core/sdk-core-protos/build.rs +9 -1
- package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
- package/sdk-core/test-utils/Cargo.toml +3 -3
- package/sdk-core/test-utils/src/canned_histories.rs +58 -0
- package/sdk-core/test-utils/src/lib.rs +14 -10
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +141 -0
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
- package/sdk-core/tests/load_tests.rs +2 -1
- package/sdk-core/tests/main.rs +10 -0
- package/src/conversions.rs +138 -91
- package/src/helpers.rs +190 -0
- package/src/lib.rs +10 -912
- package/src/runtime.rs +436 -0
- package/src/testing.rs +67 -0
- package/src/worker.rs +465 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
ClientOptions,
|
|
3
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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
|
-
.
|
|
103
|
+
.workflow_client()
|
|
104
104
|
.get_workflow_execution_history(GetWorkflowExecutionHistoryRequest {
|
|
105
105
|
namespace: self.info.namespace.to_string(),
|
|
106
106
|
execution: Some(WorkflowExecution {
|
package/sdk-core/core/Cargo.toml
CHANGED
|
@@ -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.
|
|
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.
|
|
42
|
-
prost-types = "0.
|
|
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.
|
|
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 = "
|
|
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.
|
|
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.
|
|
96
|
+
tonic-build = "0.8"
|
|
88
97
|
|
|
89
98
|
[[test]]
|
|
90
99
|
name = "integ_tests"
|