@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.
- package/Cargo.lock +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- 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/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +207 -108
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +139 -151
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
use crate::{
|
|
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
|
-
|
|
27
|
-
///
|
|
28
|
-
|
|
29
|
-
|
|
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>
|
|
34
|
-
/// Use the provided retry config with the provided
|
|
35
|
-
pub const fn new(
|
|
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
|
-
|
|
41
|
+
client,
|
|
38
42
|
retry_config,
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
impl<SG
|
|
44
|
-
|
|
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 =
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
#[
|
|
97
|
-
|
|
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, $
|
|
143
|
-
|
|
144
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
429
|
+
retry_call!(self, list_namespaces,)
|
|
402
430
|
}
|
|
403
431
|
|
|
404
|
-
fn get_options(&self) -> &
|
|
405
|
-
self.
|
|
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::
|
|
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
|
|
429
|
-
|
|
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
|
|
434
|
-
let result =
|
|
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
|
|
454
|
-
|
|
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
|
-
|
|
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
|
|
463
|
-
let result =
|
|
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 =
|
|
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
|
|
476
|
-
|
|
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
|
-
|
|
514
|
+
mock_client
|
|
481
515
|
.expect_cancel_activity_task()
|
|
482
516
|
.returning(|_, _| Ok(Default::default()))
|
|
483
517
|
.times(1);
|
|
484
518
|
|
|
485
|
-
let
|
|
486
|
-
let result =
|
|
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
|
|
497
|
-
|
|
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
|
-
|
|
535
|
+
mock_client
|
|
502
536
|
.expect_poll_workflow_task()
|
|
503
537
|
.returning(|_, _| Ok(Default::default()))
|
|
504
538
|
.times(1);
|
|
505
|
-
|
|
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
|
-
|
|
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
|
|
548
|
+
let retry_client = RetryClient::new(mock_client, Default::default());
|
|
515
549
|
|
|
516
|
-
let result =
|
|
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 =
|
|
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
|
|
529
|
-
|
|
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
|
-
|
|
569
|
+
mock_client
|
|
534
570
|
.expect_poll_workflow_task()
|
|
535
571
|
.returning(|_, _| Ok(Default::default()))
|
|
536
572
|
.times(1);
|
|
537
|
-
|
|
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
|
-
|
|
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
|
|
582
|
+
let retry_client = RetryClient::new(mock_client, Default::default());
|
|
547
583
|
|
|
548
|
-
let result =
|
|
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 =
|
|
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
|
}
|
package/sdk-core/core/Cargo.toml
CHANGED
|
@@ -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.
|
|
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.
|
|
34
|
-
opentelemetry-otlp = { version = "0.
|
|
35
|
-
opentelemetry-prometheus = "0.
|
|
36
|
-
parking_lot = { version = "0.
|
|
37
|
-
prometheus = "0.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
+
}
|