@temporalio/core-bridge 1.1.0 → 1.4.0
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 +765 -128
- package/Cargo.toml +2 -2
- package/common.js +7 -3
- package/index.d.ts +118 -5
- package/index.js +2 -6
- package/package.json +2 -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/.buildkite/pipeline.yml +2 -0
- package/sdk-core/.cargo/config.toml +1 -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/bridge-ffi/src/lib.rs +2 -2
- package/sdk-core/client/Cargo.toml +7 -5
- package/sdk-core/client/src/lib.rs +354 -226
- package/sdk-core/client/src/metrics.rs +13 -11
- package/sdk-core/client/src/raw.rs +352 -107
- package/sdk-core/client/src/retry.rs +188 -147
- package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
- package/sdk-core/core/Cargo.toml +28 -15
- package/sdk-core/core/src/core_tests/activity_tasks.rs +98 -33
- 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 +515 -0
- package/sdk-core/core/src/lib.rs +62 -28
- package/sdk-core/core/src/pollers/mod.rs +2 -0
- 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/metrics.rs +48 -39
- package/sdk-core/core/src/telemetry/mod.rs +46 -12
- package/sdk-core/core/src/telemetry/prometheus_server.rs +17 -13
- 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/mocks.rs +1 -0
- 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 +62 -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 +3 -3
- 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 +35 -12
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
- package/sdk-core/tests/integ_tests/polling_tests.rs +2 -1
- package/sdk-core/tests/integ_tests/queries_tests.rs +5 -5
- 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 +2 -6
- 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/upsert_search_attrs.rs +8 -2
- 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 +17 -0
- package/sdk-core/tests/runner.rs +93 -0
- package/src/conversions.rs +157 -94
- 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,26 @@ 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);
|
|
32
|
+
/// Must match the method name in [crate::raw::WorkflowService]
|
|
33
|
+
const POLL_WORKFLOW_METH_NAME: &str = "poll_workflow_task_queue";
|
|
34
|
+
/// Must match the method name in [crate::raw::WorkflowService]
|
|
35
|
+
const POLL_ACTIVITY_METH_NAME: &str = "poll_activity_task_queue";
|
|
31
36
|
|
|
32
37
|
/// A wrapper for a [WorkflowClientTrait] or [crate::WorkflowService] implementor which performs
|
|
33
38
|
/// auto-retries
|
|
34
39
|
#[derive(Debug, Clone)]
|
|
35
40
|
pub struct RetryClient<SG> {
|
|
36
41
|
client: SG,
|
|
37
|
-
retry_config: RetryConfig
|
|
42
|
+
retry_config: Arc<RetryConfig>,
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
impl<SG> RetryClient<SG> {
|
|
41
46
|
/// Use the provided retry config with the provided client
|
|
42
|
-
pub
|
|
47
|
+
pub fn new(client: SG, retry_config: RetryConfig) -> Self {
|
|
43
48
|
Self {
|
|
44
49
|
client,
|
|
45
|
-
retry_config,
|
|
50
|
+
retry_config: Arc::new(retry_config),
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
53
|
}
|
|
@@ -81,9 +86,8 @@ impl<SG> RetryClient<SG> {
|
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
pub(crate) fn get_retry_config(&self, call_name: &'static str) -> RetryConfig {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
CallType::Normal => self.retry_config.clone(),
|
|
89
|
+
match CallType::from_call_name(call_name) {
|
|
90
|
+
CallType::Normal => (*self.retry_config).clone(),
|
|
87
91
|
CallType::LongPoll => RetryConfig::poll_retry_policy(),
|
|
88
92
|
}
|
|
89
93
|
}
|
|
@@ -92,40 +96,39 @@ impl<SG> RetryClient<SG> {
|
|
|
92
96
|
rtc: RetryConfig,
|
|
93
97
|
factory: F,
|
|
94
98
|
call_name: &'static str,
|
|
95
|
-
) -> FutureRetry<F, TonicErrorHandler
|
|
99
|
+
) -> FutureRetry<F, TonicErrorHandler<SystemClock>>
|
|
96
100
|
where
|
|
97
101
|
F: FnMut() -> Fut + Unpin,
|
|
98
102
|
Fut: Future<Output = Result<R>>,
|
|
99
103
|
{
|
|
100
|
-
|
|
101
|
-
FutureRetry::new(factory, TonicErrorHandler::new(rtc, call_type, call_name))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
fn determine_call_type(call_name: &str) -> CallType {
|
|
105
|
-
match call_name {
|
|
106
|
-
"poll_workflow_task" | "poll_activity_task" => CallType::LongPoll,
|
|
107
|
-
_ => CallType::Normal,
|
|
108
|
-
}
|
|
104
|
+
FutureRetry::new(factory, TonicErrorHandler::new(rtc, call_name))
|
|
109
105
|
}
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
#[derive(Debug)]
|
|
113
|
-
pub(crate) struct TonicErrorHandler {
|
|
114
|
-
backoff: ExponentialBackoff
|
|
109
|
+
pub(crate) struct TonicErrorHandler<C: Clock> {
|
|
110
|
+
backoff: ExponentialBackoff<C>,
|
|
115
111
|
max_retries: usize,
|
|
116
112
|
call_type: CallType,
|
|
117
113
|
call_name: &'static str,
|
|
118
114
|
}
|
|
119
|
-
impl TonicErrorHandler {
|
|
120
|
-
fn new(cfg: RetryConfig,
|
|
115
|
+
impl TonicErrorHandler<SystemClock> {
|
|
116
|
+
fn new(cfg: RetryConfig, call_name: &'static str) -> Self {
|
|
117
|
+
Self::new_with_clock(cfg, call_name, SystemClock::default())
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
impl<C> TonicErrorHandler<C>
|
|
121
|
+
where
|
|
122
|
+
C: Clock,
|
|
123
|
+
{
|
|
124
|
+
fn new_with_clock(cfg: RetryConfig, call_name: &'static str, clock: C) -> Self {
|
|
121
125
|
Self {
|
|
122
126
|
max_retries: cfg.max_retries,
|
|
123
|
-
call_type,
|
|
127
|
+
call_type: CallType::from_call_name(call_name),
|
|
124
128
|
call_name,
|
|
125
|
-
backoff: cfg.
|
|
129
|
+
backoff: cfg.into_exp_backoff(clock),
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
|
-
|
|
129
132
|
const fn should_log_retry_warning(&self, cur_attempt: usize) -> bool {
|
|
130
133
|
// Warn on more than 5 retries for unlimited retrying
|
|
131
134
|
if self.max_retries == 0 && cur_attempt > 5 {
|
|
@@ -144,8 +147,19 @@ pub enum CallType {
|
|
|
144
147
|
Normal,
|
|
145
148
|
LongPoll,
|
|
146
149
|
}
|
|
150
|
+
impl CallType {
|
|
151
|
+
fn from_call_name(call_name: &str) -> Self {
|
|
152
|
+
match call_name {
|
|
153
|
+
POLL_WORKFLOW_METH_NAME | POLL_ACTIVITY_METH_NAME => CallType::LongPoll,
|
|
154
|
+
_ => CallType::Normal,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
147
158
|
|
|
148
|
-
impl ErrorHandler<tonic::Status> for TonicErrorHandler
|
|
159
|
+
impl<C> ErrorHandler<tonic::Status> for TonicErrorHandler<C>
|
|
160
|
+
where
|
|
161
|
+
C: Clock,
|
|
162
|
+
{
|
|
149
163
|
type OutError = tonic::Status;
|
|
150
164
|
|
|
151
165
|
fn handle(&mut self, current_attempt: usize, e: tonic::Status) -> RetryPolicy<tonic::Status> {
|
|
@@ -154,10 +168,11 @@ impl ErrorHandler<tonic::Status> for TonicErrorHandler {
|
|
|
154
168
|
return RetryPolicy::ForwardError(e);
|
|
155
169
|
}
|
|
156
170
|
|
|
171
|
+
let is_long_poll = self.call_type == CallType::LongPoll;
|
|
157
172
|
// Long polls are OK with being cancelled or running into the timeout because there's
|
|
158
173
|
// nothing to do but retry anyway
|
|
159
|
-
let long_poll_allowed =
|
|
160
|
-
&& [Code::Cancelled, Code::DeadlineExceeded].contains(&e.code());
|
|
174
|
+
let long_poll_allowed =
|
|
175
|
+
is_long_poll && [Code::Cancelled, Code::DeadlineExceeded].contains(&e.code());
|
|
161
176
|
|
|
162
177
|
if RETRYABLE_ERROR_CODES.contains(&e.code()) || long_poll_allowed {
|
|
163
178
|
if current_attempt == 1 {
|
|
@@ -178,6 +193,10 @@ impl ErrorHandler<tonic::Status> for TonicErrorHandler {
|
|
|
178
193
|
}
|
|
179
194
|
}
|
|
180
195
|
}
|
|
196
|
+
} else if is_long_poll && self.backoff.get_elapsed_time() <= LONG_POLL_FATAL_GRACE {
|
|
197
|
+
// We permit "fatal" errors while long polling for a while, because some proxies return
|
|
198
|
+
// stupid error codes while getting ready, among other weird infra issues
|
|
199
|
+
RetryPolicy::WaitRetry(self.backoff.max_interval)
|
|
181
200
|
} else {
|
|
182
201
|
RetryPolicy::ForwardError(e)
|
|
183
202
|
}
|
|
@@ -208,6 +227,7 @@ where
|
|
|
208
227
|
task_queue: String,
|
|
209
228
|
workflow_id: String,
|
|
210
229
|
workflow_type: String,
|
|
230
|
+
request_id: Option<String>,
|
|
211
231
|
options: WorkflowOptions,
|
|
212
232
|
) -> Result<StartWorkflowExecutionResponse> {
|
|
213
233
|
retry_call!(
|
|
@@ -217,31 +237,11 @@ where
|
|
|
217
237
|
task_queue.clone(),
|
|
218
238
|
workflow_id.clone(),
|
|
219
239
|
workflow_type.clone(),
|
|
240
|
+
request_id.clone(),
|
|
220
241
|
options.clone()
|
|
221
242
|
)
|
|
222
243
|
}
|
|
223
244
|
|
|
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
245
|
async fn reset_sticky_task_queue(
|
|
246
246
|
&self,
|
|
247
247
|
workflow_id: String,
|
|
@@ -255,13 +255,6 @@ where
|
|
|
255
255
|
)
|
|
256
256
|
}
|
|
257
257
|
|
|
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
258
|
async fn complete_activity_task(
|
|
266
259
|
&self,
|
|
267
260
|
task_token: TaskToken,
|
|
@@ -335,6 +328,7 @@ where
|
|
|
335
328
|
run_id: String,
|
|
336
329
|
signal_name: String,
|
|
337
330
|
payloads: Option<Payloads>,
|
|
331
|
+
request_id: Option<String>,
|
|
338
332
|
) -> Result<SignalWorkflowExecutionResponse> {
|
|
339
333
|
retry_call!(
|
|
340
334
|
self,
|
|
@@ -342,7 +336,8 @@ where
|
|
|
342
336
|
workflow_id.clone(),
|
|
343
337
|
run_id.clone(),
|
|
344
338
|
signal_name.clone(),
|
|
345
|
-
payloads.clone()
|
|
339
|
+
payloads.clone(),
|
|
340
|
+
request_id.clone()
|
|
346
341
|
)
|
|
347
342
|
}
|
|
348
343
|
|
|
@@ -352,9 +347,11 @@ where
|
|
|
352
347
|
task_queue: String,
|
|
353
348
|
workflow_id: String,
|
|
354
349
|
workflow_type: String,
|
|
350
|
+
request_id: Option<String>,
|
|
355
351
|
options: WorkflowOptions,
|
|
356
352
|
signal_name: String,
|
|
357
353
|
signal_input: Option<Payloads>,
|
|
354
|
+
signal_header: Option<Header>,
|
|
358
355
|
) -> Result<SignalWithStartWorkflowExecutionResponse> {
|
|
359
356
|
retry_call!(
|
|
360
357
|
self,
|
|
@@ -363,9 +360,11 @@ where
|
|
|
363
360
|
task_queue.clone(),
|
|
364
361
|
workflow_id.clone(),
|
|
365
362
|
workflow_type.clone(),
|
|
363
|
+
request_id.clone(),
|
|
366
364
|
options.clone(),
|
|
367
365
|
signal_name.clone(),
|
|
368
|
-
signal_input.clone()
|
|
366
|
+
signal_input.clone(),
|
|
367
|
+
signal_header.clone()
|
|
369
368
|
)
|
|
370
369
|
}
|
|
371
370
|
|
|
@@ -430,13 +429,15 @@ where
|
|
|
430
429
|
workflow_id: String,
|
|
431
430
|
run_id: Option<String>,
|
|
432
431
|
reason: String,
|
|
432
|
+
request_id: Option<String>,
|
|
433
433
|
) -> Result<RequestCancelWorkflowExecutionResponse> {
|
|
434
434
|
retry_call!(
|
|
435
435
|
self,
|
|
436
436
|
cancel_workflow_execution,
|
|
437
437
|
workflow_id.clone(),
|
|
438
438
|
run_id.clone(),
|
|
439
|
-
reason.clone()
|
|
439
|
+
reason.clone(),
|
|
440
|
+
request_id.clone()
|
|
440
441
|
)
|
|
441
442
|
}
|
|
442
443
|
|
|
@@ -457,6 +458,59 @@ where
|
|
|
457
458
|
retry_call!(self, list_namespaces,)
|
|
458
459
|
}
|
|
459
460
|
|
|
461
|
+
async fn describe_namespace(&self, namespace: Namespace) -> Result<DescribeNamespaceResponse> {
|
|
462
|
+
retry_call!(self, describe_namespace, namespace.clone())
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async fn list_open_workflow_executions(
|
|
466
|
+
&self,
|
|
467
|
+
maximum_page_size: i32,
|
|
468
|
+
next_page_token: Vec<u8>,
|
|
469
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
470
|
+
filters: Option<ListOpenFilters>,
|
|
471
|
+
) -> Result<ListOpenWorkflowExecutionsResponse> {
|
|
472
|
+
retry_call!(
|
|
473
|
+
self,
|
|
474
|
+
list_open_workflow_executions,
|
|
475
|
+
maximum_page_size,
|
|
476
|
+
next_page_token.clone(),
|
|
477
|
+
start_time_filter.clone(),
|
|
478
|
+
filters.clone()
|
|
479
|
+
)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async fn list_closed_workflow_executions(
|
|
483
|
+
&self,
|
|
484
|
+
maximum_page_size: i32,
|
|
485
|
+
next_page_token: Vec<u8>,
|
|
486
|
+
start_time_filter: Option<StartTimeFilter>,
|
|
487
|
+
filters: Option<ListClosedFilters>,
|
|
488
|
+
) -> Result<ListClosedWorkflowExecutionsResponse> {
|
|
489
|
+
retry_call!(
|
|
490
|
+
self,
|
|
491
|
+
list_closed_workflow_executions,
|
|
492
|
+
maximum_page_size,
|
|
493
|
+
next_page_token.clone(),
|
|
494
|
+
start_time_filter.clone(),
|
|
495
|
+
filters.clone()
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async fn list_workflow_executions(
|
|
500
|
+
&self,
|
|
501
|
+
page_size: i32,
|
|
502
|
+
next_page_token: Vec<u8>,
|
|
503
|
+
query: String,
|
|
504
|
+
) -> Result<ListWorkflowExecutionsResponse> {
|
|
505
|
+
retry_call!(
|
|
506
|
+
self,
|
|
507
|
+
list_workflow_executions,
|
|
508
|
+
page_size,
|
|
509
|
+
next_page_token.clone(),
|
|
510
|
+
query.clone()
|
|
511
|
+
)
|
|
512
|
+
}
|
|
513
|
+
|
|
460
514
|
fn get_options(&self) -> &ClientOptions {
|
|
461
515
|
self.client.get_options()
|
|
462
516
|
}
|
|
@@ -466,21 +520,13 @@ where
|
|
|
466
520
|
}
|
|
467
521
|
}
|
|
468
522
|
|
|
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
523
|
#[cfg(test)]
|
|
481
524
|
mod tests {
|
|
482
525
|
use super::*;
|
|
483
526
|
use crate::MockWorkflowClientTrait;
|
|
527
|
+
use assert_matches::assert_matches;
|
|
528
|
+
use backoff::Clock;
|
|
529
|
+
use std::{ops::Add, time::Instant};
|
|
484
530
|
use tonic::Status;
|
|
485
531
|
|
|
486
532
|
#[tokio::test]
|
|
@@ -510,6 +556,13 @@ mod tests {
|
|
|
510
556
|
}
|
|
511
557
|
}
|
|
512
558
|
|
|
559
|
+
struct FixedClock(Instant);
|
|
560
|
+
impl Clock for FixedClock {
|
|
561
|
+
fn now(&self) -> Instant {
|
|
562
|
+
self.0
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
513
566
|
#[tokio::test]
|
|
514
567
|
async fn long_poll_non_retryable_errors() {
|
|
515
568
|
for code in [
|
|
@@ -521,24 +574,48 @@ mod tests {
|
|
|
521
574
|
Code::Unauthenticated,
|
|
522
575
|
Code::Unimplemented,
|
|
523
576
|
] {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
.
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
.
|
|
540
|
-
|
|
541
|
-
|
|
577
|
+
for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
578
|
+
let retry_cfg = RetryConfig::poll_retry_policy();
|
|
579
|
+
let mut err_handler = TonicErrorHandler {
|
|
580
|
+
max_retries: retry_cfg.max_retries,
|
|
581
|
+
call_type: CallType::LongPoll,
|
|
582
|
+
call_name,
|
|
583
|
+
backoff: retry_cfg.into_exp_backoff(FixedClock(Instant::now())),
|
|
584
|
+
};
|
|
585
|
+
let result = err_handler.handle(1, Status::new(code, "Ahh"));
|
|
586
|
+
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
587
|
+
err_handler.backoff.clock.0 = err_handler
|
|
588
|
+
.backoff
|
|
589
|
+
.clock
|
|
590
|
+
.0
|
|
591
|
+
.add(LONG_POLL_FATAL_GRACE + Duration::from_secs(1));
|
|
592
|
+
let result = err_handler.handle(2, Status::new(code, "Ahh"));
|
|
593
|
+
assert_matches!(result, RetryPolicy::ForwardError(_));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
#[tokio::test]
|
|
599
|
+
async fn long_poll_retryable_errors_never_fatal() {
|
|
600
|
+
for code in RETRYABLE_ERROR_CODES {
|
|
601
|
+
for call_name in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
602
|
+
let retry_cfg = RetryConfig::poll_retry_policy();
|
|
603
|
+
let mut err_handler = TonicErrorHandler {
|
|
604
|
+
max_retries: retry_cfg.max_retries,
|
|
605
|
+
call_type: CallType::LongPoll,
|
|
606
|
+
call_name,
|
|
607
|
+
backoff: retry_cfg.into_exp_backoff(FixedClock(Instant::now())),
|
|
608
|
+
};
|
|
609
|
+
let result = err_handler.handle(1, Status::new(code, "Ahh"));
|
|
610
|
+
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
611
|
+
err_handler.backoff.clock.0 = err_handler
|
|
612
|
+
.backoff
|
|
613
|
+
.clock
|
|
614
|
+
.0
|
|
615
|
+
.add(LONG_POLL_FATAL_GRACE + Duration::from_secs(1));
|
|
616
|
+
let result = err_handler.handle(2, Status::new(code, "Ahh"));
|
|
617
|
+
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
618
|
+
}
|
|
542
619
|
}
|
|
543
620
|
}
|
|
544
621
|
|
|
@@ -566,68 +643,32 @@ mod tests {
|
|
|
566
643
|
|
|
567
644
|
#[tokio::test]
|
|
568
645
|
async fn long_poll_retries_forever() {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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());
|
|
646
|
+
// A bit odd, but we don't need a real client to test the retry client passes through the
|
|
647
|
+
// correct retry config
|
|
648
|
+
let fake_retry = RetryClient::new((), Default::default());
|
|
649
|
+
for i in 1..=50 {
|
|
650
|
+
for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
651
|
+
let mut err_handler =
|
|
652
|
+
TonicErrorHandler::new(fake_retry.get_retry_config(call), call);
|
|
653
|
+
let result = err_handler.handle(i, Status::new(Code::Unknown, "Ahh"));
|
|
654
|
+
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
597
657
|
}
|
|
598
658
|
|
|
599
659
|
#[tokio::test]
|
|
600
660
|
async fn long_poll_retries_deadline_exceeded() {
|
|
661
|
+
let fake_retry = RetryClient::new((), Default::default());
|
|
601
662
|
// For some reason we will get cancelled in these situations occasionally (always?) too
|
|
602
663
|
for code in [Code::Cancelled, Code::DeadlineExceeded] {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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());
|
|
664
|
+
for call in [POLL_WORKFLOW_METH_NAME, POLL_ACTIVITY_METH_NAME] {
|
|
665
|
+
let mut err_handler =
|
|
666
|
+
TonicErrorHandler::new(fake_retry.get_retry_config(call), call);
|
|
667
|
+
for i in 1..=5 {
|
|
668
|
+
let result = err_handler.handle(i, Status::new(code, "retryable failure"));
|
|
669
|
+
assert_matches!(result, RetryPolicy::WaitRetry(_));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
631
672
|
}
|
|
632
673
|
}
|
|
633
674
|
}
|
|
@@ -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,46 @@ 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"
|
|
27
|
-
|
|
28
|
+
futures-util = "0.3"
|
|
29
|
+
governor = "0.5"
|
|
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
|
-
opentelemetry = { version = "0.
|
|
37
|
-
opentelemetry-otlp = { version = "0.
|
|
38
|
-
opentelemetry-prometheus = "0.
|
|
39
|
+
opentelemetry = { version = "0.18", features = ["rt-tokio"] }
|
|
40
|
+
opentelemetry-otlp = { version = "0.11", features = ["tokio", "metrics"] }
|
|
41
|
+
opentelemetry-prometheus = "0.11"
|
|
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"] }
|
|
53
59
|
tracing = { version = "0.1", features = ["log-always"] }
|
|
54
60
|
tracing-futures = "0.2"
|
|
55
|
-
tracing-opentelemetry = "0.
|
|
61
|
+
tracing-opentelemetry = "0.18"
|
|
56
62
|
tracing-subscriber = { version = "0.3", features = ["parking_lot", "env-filter"] }
|
|
57
63
|
url = "2.2"
|
|
58
|
-
uuid = { version = "
|
|
64
|
+
uuid = { version = "1.1", features = ["v4"] }
|
|
65
|
+
zip = "0.6"
|
|
59
66
|
|
|
60
67
|
# 1st party local deps
|
|
61
68
|
[dependencies.temporal-sdk-core-api]
|
|
@@ -78,13 +85,13 @@ version = "0.1"
|
|
|
78
85
|
[dev-dependencies]
|
|
79
86
|
assert_matches = "1.4"
|
|
80
87
|
bimap = "0.6.1"
|
|
81
|
-
criterion = "0.
|
|
82
|
-
rstest = "0.
|
|
88
|
+
criterion = "0.4"
|
|
89
|
+
rstest = "0.15"
|
|
83
90
|
temporal-sdk-core-test-utils = { path = "../test-utils" }
|
|
84
91
|
temporal-sdk = { path = "../sdk" }
|
|
85
92
|
|
|
86
93
|
[build-dependencies]
|
|
87
|
-
tonic-build = "0.
|
|
94
|
+
tonic-build = "0.8"
|
|
88
95
|
|
|
89
96
|
[[test]]
|
|
90
97
|
name = "integ_tests"
|
|
@@ -101,3 +108,9 @@ test = false
|
|
|
101
108
|
[[bench]]
|
|
102
109
|
name = "workflow_replay"
|
|
103
110
|
harness = false
|
|
111
|
+
|
|
112
|
+
# This is maybe a bit hacky, but we call the runner an "example" because that gets it compiling with
|
|
113
|
+
# the dev-dependencies, which we want.
|
|
114
|
+
[[example]]
|
|
115
|
+
name = "integ_runner"
|
|
116
|
+
path = "../tests/runner.rs"
|