@temporalio/core-bridge 1.5.2 → 1.6.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 +255 -48
- package/package.json +4 -4
- 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/pipeline.yml +1 -3
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +28 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +9 -5
- package/sdk-core/client/src/lib.rs +211 -36
- package/sdk-core/client/src/raw.rs +1 -1
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +23 -9
- package/sdk-core/core/src/abstractions.rs +11 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +6 -5
- package/sdk-core/core/src/core_tests/local_activities.rs +263 -22
- package/sdk-core/core/src/core_tests/queries.rs +2 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +249 -5
- package/sdk-core/core/src/ephemeral_server/mod.rs +5 -6
- package/sdk-core/core/src/lib.rs +2 -0
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/mod.rs +23 -8
- package/sdk-core/core/src/test_help/mod.rs +8 -1
- package/sdk-core/core/src/worker/activities/local_activities.rs +259 -125
- package/sdk-core/core/src/worker/activities.rs +3 -2
- package/sdk-core/core/src/worker/mod.rs +53 -26
- package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- package/sdk-core/core/src/worker/workflow/history_update.rs +835 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -17
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +73 -51
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -3
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +89 -58
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -7
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +21 -9
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1021 -360
- package/sdk-core/core/src/worker/workflow/mod.rs +306 -346
- package/sdk-core/core/src/worker/workflow/run_cache.rs +29 -53
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +115 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +444 -714
- package/sdk-core/core-api/Cargo.toml +2 -0
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +6 -2
- package/sdk-core/core-api/src/worker.rs +14 -1
- package/sdk-core/etc/deps.svg +115 -140
- package/sdk-core/etc/regen-depgraph.sh +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -6
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -3
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- package/sdk-core/protos/api_upstream/Makefile +5 -5
- package/sdk-core/protos/api_upstream/build/go.mod +7 -0
- package/sdk-core/protos/api_upstream/build/go.sum +5 -0
- package/sdk-core/protos/api_upstream/build/tools.go +29 -0
- package/sdk-core/protos/api_upstream/go.mod +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +12 -19
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +3 -3
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -2
- package/sdk-core/protos/api_upstream/temporal/api/{update/v1/message.proto → enums/v1/interaction_type.proto} +11 -18
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +2 -13
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -19
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +13 -8
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- package/sdk-core/sdk/Cargo.toml +4 -3
- package/sdk-core/sdk/src/lib.rs +87 -21
- package/sdk-core/sdk/src/workflow_future.rs +7 -12
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- package/sdk-core/sdk-core-protos/build.rs +36 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +26 -19
- package/sdk-core/sdk-core-protos/src/history_info.rs +4 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +78 -34
- package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +50 -18
- package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- package/sdk-core/test-utils/src/workflows.rs +29 -0
- package/sdk-core/tests/fuzzy_workflow.rs +130 -0
- package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +114 -7
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -2
- package/sdk-core/tests/integ_tests/metrics_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -39
- package/sdk-core/tests/integ_tests/queries_tests.rs +2 -127
- package/sdk-core/tests/integ_tests/visibility_tests.rs +52 -5
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +74 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +5 -13
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +2 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +69 -197
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +4 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +5 -6
- package/sdk-core/tests/main.rs +2 -12
- package/sdk-core/tests/runner.rs +71 -34
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/sdk-core/bridge-ffi/Cargo.toml +0 -24
- package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- package/sdk-core/bridge-ffi/build.rs +0 -25
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
- package/sdk-core/bridge-ffi/src/lib.rs +0 -746
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- package/sdk-core/sdk/src/conversions.rs +0 -8
|
@@ -2,16 +2,18 @@ use assert_matches::assert_matches;
|
|
|
2
2
|
use futures::{future::join_all, sink, stream::FuturesUnordered, StreamExt};
|
|
3
3
|
use std::time::{Duration, Instant};
|
|
4
4
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
|
|
5
|
-
use temporal_sdk::{ActContext, ActivityOptions, WfContext};
|
|
5
|
+
use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
|
|
6
6
|
use temporal_sdk_core_protos::coresdk::{
|
|
7
7
|
activity_result::ActivityExecutionResult, activity_task::activity_task as act_task,
|
|
8
8
|
workflow_commands::ActivityCancellationType, ActivityTaskCompletion, AsJsonPayloadExt,
|
|
9
9
|
};
|
|
10
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
10
|
+
use temporal_sdk_core_test_utils::{workflows::la_problem_workflow, CoreWfStarter};
|
|
11
|
+
|
|
12
|
+
mod fuzzy_workflow;
|
|
11
13
|
|
|
12
14
|
#[tokio::test]
|
|
13
15
|
async fn activity_load() {
|
|
14
|
-
const CONCURRENCY: usize =
|
|
16
|
+
const CONCURRENCY: usize = 512;
|
|
15
17
|
|
|
16
18
|
let mut starter = CoreWfStarter::new("activity_load");
|
|
17
19
|
starter
|
|
@@ -54,7 +56,7 @@ async fn activity_load() {
|
|
|
54
56
|
worker.register_wf(wf_type.to_owned(), wf_fn);
|
|
55
57
|
join_all((0..CONCURRENCY).map(|i| {
|
|
56
58
|
let worker = &worker;
|
|
57
|
-
let wf_id = format!("activity_load_{}"
|
|
59
|
+
let wf_id = format!("activity_load_{i}");
|
|
58
60
|
async move {
|
|
59
61
|
worker
|
|
60
62
|
.submit_wf(
|
|
@@ -153,7 +155,7 @@ async fn workflow_load() {
|
|
|
153
155
|
|
|
154
156
|
let mut workflow_handles = vec![];
|
|
155
157
|
for i in 0..num_workflows {
|
|
156
|
-
let wfid = format!("{}_{}"
|
|
158
|
+
let wfid = format!("{wf_name}_{i}");
|
|
157
159
|
let rid = worker
|
|
158
160
|
.submit_wf(
|
|
159
161
|
wfid.clone(),
|
|
@@ -171,7 +173,7 @@ async fn workflow_load() {
|
|
|
171
173
|
let sends: FuturesUnordered<_> = (0..num_workflows)
|
|
172
174
|
.map(|i| {
|
|
173
175
|
client.signal_workflow_execution(
|
|
174
|
-
format!("{}_{}"
|
|
176
|
+
format!("{wf_name}_{i}"),
|
|
175
177
|
"".to_string(),
|
|
176
178
|
SIGNAME.to_string(),
|
|
177
179
|
None,
|
|
@@ -187,5 +189,110 @@ async fn workflow_load() {
|
|
|
187
189
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
188
190
|
}
|
|
189
191
|
};
|
|
190
|
-
tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}}
|
|
192
|
+
tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
|
196
|
+
async fn evict_while_la_running_no_interference() {
|
|
197
|
+
let wf_name = "evict_while_la_running_no_interference";
|
|
198
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
199
|
+
starter.max_local_at(20);
|
|
200
|
+
starter.max_cached_workflows(20);
|
|
201
|
+
// Though it doesn't make sense to set wft higher than cached workflows, leaving this commented
|
|
202
|
+
// introduces more instability that can be useful in the test.
|
|
203
|
+
// starter.max_wft(20);
|
|
204
|
+
let mut worker = starter.worker().await;
|
|
205
|
+
|
|
206
|
+
worker.register_wf(wf_name.to_owned(), la_problem_workflow);
|
|
207
|
+
worker.register_activity("delay", |_: ActContext, _: String| async {
|
|
208
|
+
tokio::time::sleep(Duration::from_secs(15)).await;
|
|
209
|
+
Ok(())
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
let client = starter.get_client().await;
|
|
213
|
+
let subfs = FuturesUnordered::new();
|
|
214
|
+
for i in 1..100 {
|
|
215
|
+
let wf_id = format!("{wf_name}-{i}");
|
|
216
|
+
let run_id = worker
|
|
217
|
+
.submit_wf(
|
|
218
|
+
&wf_id,
|
|
219
|
+
wf_name.to_owned(),
|
|
220
|
+
vec![],
|
|
221
|
+
WorkflowOptions::default(),
|
|
222
|
+
)
|
|
223
|
+
.await
|
|
224
|
+
.unwrap();
|
|
225
|
+
let cw = worker.core_worker.clone();
|
|
226
|
+
let client = client.clone();
|
|
227
|
+
subfs.push(async move {
|
|
228
|
+
// Evict the workflow
|
|
229
|
+
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
230
|
+
cw.request_workflow_eviction(&run_id);
|
|
231
|
+
// Wake up workflow by sending signal
|
|
232
|
+
client
|
|
233
|
+
.signal_workflow_execution(
|
|
234
|
+
wf_id,
|
|
235
|
+
run_id.clone(),
|
|
236
|
+
"whaatever".to_string(),
|
|
237
|
+
None,
|
|
238
|
+
None,
|
|
239
|
+
)
|
|
240
|
+
.await
|
|
241
|
+
.unwrap();
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
let runf = async {
|
|
245
|
+
worker.run_until_done().await.unwrap();
|
|
246
|
+
};
|
|
247
|
+
tokio::join!(subfs.collect::<Vec<_>>(), runf);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()> {
|
|
251
|
+
for _ in 0..120 {
|
|
252
|
+
let mut futs = vec![];
|
|
253
|
+
for _ in 0..100 {
|
|
254
|
+
futs.push(ctx.timer(Duration::from_millis(100)));
|
|
255
|
+
}
|
|
256
|
+
join_all(futs).await;
|
|
257
|
+
}
|
|
258
|
+
Ok(().into())
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#[tokio::test]
|
|
262
|
+
async fn can_paginate_long_history() {
|
|
263
|
+
let wf_name = "can_paginate_long_history";
|
|
264
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
265
|
+
// Do not use sticky queues so we are forced to paginate once history gets long
|
|
266
|
+
starter.max_cached_workflows(0);
|
|
267
|
+
|
|
268
|
+
let mut worker = starter.worker().await;
|
|
269
|
+
worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
|
|
270
|
+
let run_id = worker
|
|
271
|
+
.submit_wf(
|
|
272
|
+
wf_name.to_owned(),
|
|
273
|
+
wf_name.to_owned(),
|
|
274
|
+
vec![],
|
|
275
|
+
WorkflowOptions::default(),
|
|
276
|
+
)
|
|
277
|
+
.await
|
|
278
|
+
.unwrap();
|
|
279
|
+
let client = starter.get_client().await;
|
|
280
|
+
tokio::spawn(async move {
|
|
281
|
+
loop {
|
|
282
|
+
for _ in 0..10 {
|
|
283
|
+
client
|
|
284
|
+
.signal_workflow_execution(
|
|
285
|
+
wf_name.to_owned(),
|
|
286
|
+
run_id.clone(),
|
|
287
|
+
"sig".to_string(),
|
|
288
|
+
None,
|
|
289
|
+
None,
|
|
290
|
+
)
|
|
291
|
+
.await
|
|
292
|
+
.unwrap();
|
|
293
|
+
}
|
|
294
|
+
tokio::time::sleep(Duration::from_secs(3)).await;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
worker.run_until_done().await.unwrap();
|
|
191
298
|
}
|
|
@@ -13,7 +13,10 @@ use temporal_sdk_core_protos::{
|
|
|
13
13
|
workflow_completion::WorkflowActivationCompletion,
|
|
14
14
|
ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
|
|
15
15
|
},
|
|
16
|
-
temporal::api::
|
|
16
|
+
temporal::api::{
|
|
17
|
+
common::v1::{Payload, RetryPolicy},
|
|
18
|
+
enums::v1::TimeoutType,
|
|
19
|
+
},
|
|
17
20
|
};
|
|
18
21
|
use temporal_sdk_core_test_utils::{
|
|
19
22
|
init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter, WorkerTestHelpers,
|
|
@@ -196,7 +199,7 @@ async fn activity_doesnt_heartbeat_hits_timeout_then_completes() {
|
|
|
196
199
|
..Default::default()
|
|
197
200
|
})
|
|
198
201
|
.await;
|
|
199
|
-
|
|
202
|
+
assert_eq!(res.timed_out(), Some(TimeoutType::Heartbeat));
|
|
200
203
|
Ok(().into())
|
|
201
204
|
});
|
|
202
205
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
|
-
use futures::future::join_all;
|
|
3
2
|
use std::time::Duration;
|
|
4
|
-
use temporal_client::WorkflowOptions;
|
|
5
|
-
use temporal_sdk::{WfContext, WorkflowResult};
|
|
6
3
|
use temporal_sdk_core_protos::coresdk::{
|
|
7
4
|
activity_task::activity_task as act_task,
|
|
8
5
|
workflow_activation::{workflow_activation_job, FireTimer, WorkflowActivationJob},
|
|
@@ -11,7 +8,7 @@ use temporal_sdk_core_protos::coresdk::{
|
|
|
11
8
|
IntoCompletion,
|
|
12
9
|
};
|
|
13
10
|
use temporal_sdk_core_test_utils::{
|
|
14
|
-
init_core_and_create_wf, schedule_activity_cmd,
|
|
11
|
+
init_core_and_create_wf, schedule_activity_cmd, WorkerTestHelpers,
|
|
15
12
|
};
|
|
16
13
|
use tokio::time::timeout;
|
|
17
14
|
|
|
@@ -96,38 +93,3 @@ async fn out_of_order_completion_doesnt_hang() {
|
|
|
96
93
|
|
|
97
94
|
jh.await.unwrap();
|
|
98
95
|
}
|
|
99
|
-
|
|
100
|
-
pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()> {
|
|
101
|
-
for _ in 0..20 {
|
|
102
|
-
let mut futs = vec![];
|
|
103
|
-
for _ in 0..1000 {
|
|
104
|
-
futs.push(ctx.timer(Duration::from_millis(100)));
|
|
105
|
-
}
|
|
106
|
-
join_all(futs).await;
|
|
107
|
-
}
|
|
108
|
-
Ok(().into())
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Ignored for now because I can't actually get this to produce pages. Need to generate some
|
|
112
|
-
// large payloads I think.
|
|
113
|
-
#[tokio::test]
|
|
114
|
-
#[ignore]
|
|
115
|
-
async fn can_paginate_long_history() {
|
|
116
|
-
let wf_name = "can_paginate_long_history";
|
|
117
|
-
let mut starter = CoreWfStarter::new(wf_name);
|
|
118
|
-
// Do not use sticky queues so we are forced to paginate once history gets long
|
|
119
|
-
starter.max_cached_workflows(0);
|
|
120
|
-
|
|
121
|
-
let mut worker = starter.worker().await;
|
|
122
|
-
worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
|
|
123
|
-
worker
|
|
124
|
-
.submit_wf(
|
|
125
|
-
wf_name.to_owned(),
|
|
126
|
-
wf_name.to_owned(),
|
|
127
|
-
vec![],
|
|
128
|
-
WorkflowOptions::default(),
|
|
129
|
-
)
|
|
130
|
-
.await
|
|
131
|
-
.unwrap();
|
|
132
|
-
worker.run_until_done().await.unwrap();
|
|
133
|
-
}
|
|
@@ -10,7 +10,7 @@ use temporal_sdk_core_protos::{
|
|
|
10
10
|
},
|
|
11
11
|
temporal::api::{failure::v1::Failure, query::v1::WorkflowQuery},
|
|
12
12
|
};
|
|
13
|
-
use temporal_sdk_core_test_utils::{init_core_and_create_wf,
|
|
13
|
+
use temporal_sdk_core_test_utils::{init_core_and_create_wf, WorkerTestHelpers};
|
|
14
14
|
|
|
15
15
|
#[tokio::test]
|
|
16
16
|
async fn simple_query_legacy() {
|
|
@@ -112,7 +112,7 @@ async fn simple_query_legacy() {
|
|
|
112
112
|
async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
113
113
|
let query_resp = b"response";
|
|
114
114
|
let mut starter =
|
|
115
|
-
init_core_and_create_wf(&format!("query_after_execution_complete-{}"
|
|
115
|
+
init_core_and_create_wf(&format!("query_after_execution_complete-{do_evict}")).await;
|
|
116
116
|
let core = &starter.get_worker().await;
|
|
117
117
|
let workflow_id = &starter.get_task_queue().to_string();
|
|
118
118
|
|
|
@@ -208,131 +208,6 @@ async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
|
208
208
|
core.shutdown().await;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
#[ignore]
|
|
212
|
-
#[tokio::test]
|
|
213
|
-
async fn repros_query_dropped_on_floor() {
|
|
214
|
-
// This test reliably repros the server dropping one of the two simultaneously issued queries.
|
|
215
|
-
let q1_resp = b"query_1_resp";
|
|
216
|
-
let q2_resp = b"query_2_resp";
|
|
217
|
-
let mut wf_starter = CoreWfStarter::new("repros_query_dropped_on_floor");
|
|
218
|
-
// Easiest way I discovered to reliably trigger new query path is with a WFT timeout
|
|
219
|
-
wf_starter.wft_timeout(Duration::from_secs(1));
|
|
220
|
-
let core = wf_starter.get_worker().await;
|
|
221
|
-
let task_q = wf_starter.get_task_queue().to_string();
|
|
222
|
-
wf_starter.start_wf().await;
|
|
223
|
-
let client = wf_starter.get_client().await;
|
|
224
|
-
|
|
225
|
-
let task = core.poll_workflow_activation().await.unwrap();
|
|
226
|
-
core.complete_timer(&task.run_id, 1, Duration::from_millis(500))
|
|
227
|
-
.await;
|
|
228
|
-
|
|
229
|
-
// Poll for a task we will time out
|
|
230
|
-
let task = core.poll_workflow_activation().await.unwrap();
|
|
231
|
-
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
232
|
-
// Complete now-timed-out task (add a new timer)
|
|
233
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
234
|
-
task.run_id.clone(),
|
|
235
|
-
vec![],
|
|
236
|
-
))
|
|
237
|
-
.await
|
|
238
|
-
.unwrap();
|
|
239
|
-
|
|
240
|
-
let run_id = task.run_id.to_string();
|
|
241
|
-
let q1_fut = async {
|
|
242
|
-
client
|
|
243
|
-
.query_workflow_execution(
|
|
244
|
-
task_q.clone(),
|
|
245
|
-
run_id,
|
|
246
|
-
WorkflowQuery {
|
|
247
|
-
query_type: "query_1".to_string(),
|
|
248
|
-
query_args: Some(b"hi 1".into()),
|
|
249
|
-
header: None,
|
|
250
|
-
},
|
|
251
|
-
)
|
|
252
|
-
.await
|
|
253
|
-
.unwrap()
|
|
254
|
-
};
|
|
255
|
-
let run_id = task.run_id.to_string();
|
|
256
|
-
let q2_fut = async {
|
|
257
|
-
client
|
|
258
|
-
.query_workflow_execution(
|
|
259
|
-
task_q.clone(),
|
|
260
|
-
run_id,
|
|
261
|
-
WorkflowQuery {
|
|
262
|
-
query_type: "query_2".to_string(),
|
|
263
|
-
query_args: Some(b"hi 2".into()),
|
|
264
|
-
header: None,
|
|
265
|
-
},
|
|
266
|
-
)
|
|
267
|
-
.await
|
|
268
|
-
.unwrap()
|
|
269
|
-
};
|
|
270
|
-
let workflow_completions_future = async {
|
|
271
|
-
let mut seen_q1 = false;
|
|
272
|
-
let mut seen_q2 = false;
|
|
273
|
-
while !seen_q1 || !seen_q2 {
|
|
274
|
-
let task = core.poll_workflow_activation().await.unwrap();
|
|
275
|
-
|
|
276
|
-
if matches!(
|
|
277
|
-
task.jobs[0],
|
|
278
|
-
WorkflowActivationJob {
|
|
279
|
-
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
280
|
-
}
|
|
281
|
-
) {
|
|
282
|
-
let task = core.poll_workflow_activation().await.unwrap();
|
|
283
|
-
core.complete_timer(&task.run_id, 1, Duration::from_millis(500))
|
|
284
|
-
.await;
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if matches!(
|
|
289
|
-
task.jobs[0],
|
|
290
|
-
WorkflowActivationJob {
|
|
291
|
-
variant: Some(workflow_activation_job::Variant::FireTimer(_)),
|
|
292
|
-
}
|
|
293
|
-
) {
|
|
294
|
-
// If we get the timer firing after replay, be done.
|
|
295
|
-
core.complete_execution(&task.run_id).await;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// There should be a query job (really, there should be both... server only sends one?)
|
|
299
|
-
let query = assert_matches!(
|
|
300
|
-
task.jobs.as_slice(),
|
|
301
|
-
[WorkflowActivationJob {
|
|
302
|
-
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
303
|
-
}] => q
|
|
304
|
-
);
|
|
305
|
-
let resp = if query.query_type == "query_1" {
|
|
306
|
-
seen_q1 = true;
|
|
307
|
-
q1_resp
|
|
308
|
-
} else {
|
|
309
|
-
seen_q2 = true;
|
|
310
|
-
q2_resp
|
|
311
|
-
};
|
|
312
|
-
// Complete the query
|
|
313
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
314
|
-
task.run_id,
|
|
315
|
-
vec![QueryResult {
|
|
316
|
-
query_id: query.query_id.clone(),
|
|
317
|
-
variant: Some(
|
|
318
|
-
QuerySuccess {
|
|
319
|
-
response: Some(resp.into()),
|
|
320
|
-
}
|
|
321
|
-
.into(),
|
|
322
|
-
),
|
|
323
|
-
}
|
|
324
|
-
.into()],
|
|
325
|
-
))
|
|
326
|
-
.await
|
|
327
|
-
.unwrap();
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
let (q1_res, q2_res, _) = tokio::join!(q1_fut, q2_fut, workflow_completions_future);
|
|
331
|
-
// Ensure query responses are as expected
|
|
332
|
-
assert_eq!(&q1_res.unwrap()[0].data, q1_resp);
|
|
333
|
-
assert_eq!(&q2_res.unwrap()[0].data, q2_resp);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
211
|
#[tokio::test]
|
|
337
212
|
async fn fail_legacy_query() {
|
|
338
213
|
let query_err = "oh no broken";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
use assert_matches::assert_matches;
|
|
2
2
|
use std::{sync::Arc, time::Duration};
|
|
3
3
|
use temporal_client::{
|
|
4
|
-
ListClosedFilters, ListOpenFilters, Namespace,
|
|
5
|
-
|
|
4
|
+
ListClosedFilters, ListOpenFilters, Namespace, RegisterNamespaceOptions, StartTimeFilter,
|
|
5
|
+
WorkflowClientTrait, WorkflowExecutionFilter,
|
|
6
6
|
};
|
|
7
7
|
use temporal_sdk_core_protos::coresdk::workflow_activation::{
|
|
8
8
|
workflow_activation_job, WorkflowActivationJob,
|
|
@@ -10,6 +10,7 @@ use temporal_sdk_core_protos::coresdk::workflow_activation::{
|
|
|
10
10
|
use temporal_sdk_core_test_utils::{
|
|
11
11
|
get_integ_server_options, CoreWfStarter, WorkerTestHelpers, NAMESPACE,
|
|
12
12
|
};
|
|
13
|
+
use tokio::time::sleep;
|
|
13
14
|
|
|
14
15
|
#[tokio::test]
|
|
15
16
|
async fn client_list_open_closed_workflow_executions() {
|
|
@@ -22,9 +23,7 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
22
23
|
let latest = earliest + Duration::from_secs(60);
|
|
23
24
|
|
|
24
25
|
// start workflow
|
|
25
|
-
let run_id = starter
|
|
26
|
-
.start_wf_with_id(wf_name.to_owned(), WorkflowOptions::default())
|
|
27
|
-
.await;
|
|
26
|
+
let run_id = starter.start_wf_with_id(wf_name.to_owned()).await;
|
|
28
27
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
29
28
|
assert_matches!(
|
|
30
29
|
task.jobs.as_slice(),
|
|
@@ -52,6 +51,7 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
52
51
|
|
|
53
52
|
// Complete workflow
|
|
54
53
|
core.complete_execution(&task.run_id).await;
|
|
54
|
+
core.shutdown().await;
|
|
55
55
|
|
|
56
56
|
// List above CLOSED workflow
|
|
57
57
|
let start_time_filter = StartTimeFilter {
|
|
@@ -76,6 +76,53 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
76
76
|
assert_eq!(workflow.execution.as_ref().unwrap().workflow_id, wf_name);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
#[tokio::test]
|
|
80
|
+
async fn client_create_namespace() {
|
|
81
|
+
let client = Arc::new(
|
|
82
|
+
get_integ_server_options()
|
|
83
|
+
.connect(NAMESPACE.to_owned(), None, None)
|
|
84
|
+
.await
|
|
85
|
+
.expect("Must connect"),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
let register_options = RegisterNamespaceOptions::builder()
|
|
89
|
+
.namespace("test-create-namespace")
|
|
90
|
+
.description("it's alive")
|
|
91
|
+
.build()
|
|
92
|
+
.unwrap();
|
|
93
|
+
|
|
94
|
+
client
|
|
95
|
+
.register_namespace(register_options.clone())
|
|
96
|
+
.await
|
|
97
|
+
.unwrap();
|
|
98
|
+
|
|
99
|
+
//#Hack, not sure how else to wait for a proper response. RegisterNamespace isn't safe to read
|
|
100
|
+
//after write
|
|
101
|
+
let mut attempts = 0;
|
|
102
|
+
let wait_time = Duration::from_secs(1);
|
|
103
|
+
loop {
|
|
104
|
+
attempts += 1;
|
|
105
|
+
let resp = client
|
|
106
|
+
.describe_namespace(Namespace::Name(register_options.namespace.clone()))
|
|
107
|
+
.await;
|
|
108
|
+
|
|
109
|
+
match resp {
|
|
110
|
+
Ok(n) => {
|
|
111
|
+
let namespace_info = n.namespace_info.unwrap();
|
|
112
|
+
assert_eq!(namespace_info.name, register_options.namespace);
|
|
113
|
+
assert_eq!(namespace_info.description, register_options.description);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
_ => {
|
|
117
|
+
if attempts == 12 {
|
|
118
|
+
panic!("failed to query registered namespace");
|
|
119
|
+
}
|
|
120
|
+
sleep(wait_time).await
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
79
126
|
#[tokio::test]
|
|
80
127
|
async fn client_describe_namespace() {
|
|
81
128
|
let client = Arc::new(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
use anyhow::anyhow;
|
|
1
2
|
use assert_matches::assert_matches;
|
|
2
3
|
use std::time::Duration;
|
|
3
4
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
|
|
@@ -205,6 +206,78 @@ async fn activity_non_retryable_failure() {
|
|
|
205
206
|
core.complete_execution(&task.run_id).await;
|
|
206
207
|
}
|
|
207
208
|
|
|
209
|
+
#[tokio::test]
|
|
210
|
+
async fn activity_non_retryable_failure_with_error() {
|
|
211
|
+
let mut starter = init_core_and_create_wf("activity_non_retryable_failure").await;
|
|
212
|
+
let core = starter.get_worker().await;
|
|
213
|
+
let task_q = starter.get_task_queue();
|
|
214
|
+
let activity_id = "act-1";
|
|
215
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
216
|
+
// Complete workflow task and schedule activity
|
|
217
|
+
core.complete_workflow_activation(
|
|
218
|
+
schedule_activity_cmd(
|
|
219
|
+
0,
|
|
220
|
+
task_q,
|
|
221
|
+
activity_id,
|
|
222
|
+
ActivityCancellationType::TryCancel,
|
|
223
|
+
Duration::from_secs(60),
|
|
224
|
+
Duration::from_secs(60),
|
|
225
|
+
)
|
|
226
|
+
.into_completion(task.run_id),
|
|
227
|
+
)
|
|
228
|
+
.await
|
|
229
|
+
.unwrap();
|
|
230
|
+
// Poll activity and verify that it's been scheduled with correct parameters
|
|
231
|
+
let task = core.poll_activity_task().await.unwrap();
|
|
232
|
+
assert_matches!(
|
|
233
|
+
task.variant,
|
|
234
|
+
Some(act_task::Variant::Start(start_activity)) => {
|
|
235
|
+
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
// Fail activity with non-retryable error
|
|
239
|
+
let failure = Failure::application_failure_from_error(anyhow!("activity failed"), true);
|
|
240
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
241
|
+
task_token: task.task_token,
|
|
242
|
+
result: Some(ActivityExecutionResult::fail(failure.clone())),
|
|
243
|
+
})
|
|
244
|
+
.await
|
|
245
|
+
.unwrap();
|
|
246
|
+
// Poll workflow task and verify that activity has failed.
|
|
247
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
248
|
+
assert_matches!(
|
|
249
|
+
task.jobs.as_slice(),
|
|
250
|
+
[
|
|
251
|
+
WorkflowActivationJob {
|
|
252
|
+
variant: Some(workflow_activation_job::Variant::ResolveActivity(
|
|
253
|
+
ResolveActivity {seq, result: Some(ActivityResolution{
|
|
254
|
+
status: Some(act_res::Status::Failed(activity_result::Failure{
|
|
255
|
+
failure: Some(f),
|
|
256
|
+
}))})}
|
|
257
|
+
)),
|
|
258
|
+
},
|
|
259
|
+
] => {
|
|
260
|
+
assert_eq!(*seq, 0);
|
|
261
|
+
assert_eq!(f, &Failure{
|
|
262
|
+
message: "Activity task failed".to_owned(),
|
|
263
|
+
cause: Some(Box::new(failure)),
|
|
264
|
+
failure_info: Some(FailureInfo::ActivityFailureInfo(ActivityFailureInfo{
|
|
265
|
+
activity_id: "act-1".to_owned(),
|
|
266
|
+
activity_type: Some(ActivityType {
|
|
267
|
+
name: "test_activity".to_owned(),
|
|
268
|
+
}),
|
|
269
|
+
scheduled_event_id: 5,
|
|
270
|
+
started_event_id: 6,
|
|
271
|
+
identity: "integ_tester".to_owned(),
|
|
272
|
+
retry_state: RetryState::NonRetryableFailure as i32,
|
|
273
|
+
})),
|
|
274
|
+
..Default::default()
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
core.complete_execution(&task.run_id).await;
|
|
279
|
+
}
|
|
280
|
+
|
|
208
281
|
#[tokio::test]
|
|
209
282
|
async fn activity_retry() {
|
|
210
283
|
let mut starter = init_core_and_create_wf("activity_retry").await;
|
|
@@ -822,7 +895,7 @@ async fn it_can_complete_async() {
|
|
|
822
895
|
Some(act_res::Status::Completed(activity_result::Success { result })) => result
|
|
823
896
|
.map(|p| String::from_json_payload(&p).unwrap())
|
|
824
897
|
.unwrap(),
|
|
825
|
-
_ => panic!("activity task failed {:?}"
|
|
898
|
+
_ => panic!("activity task failed {activity_resolution:?}"),
|
|
826
899
|
};
|
|
827
900
|
|
|
828
901
|
assert_eq!(&res, async_response);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use std::time::Duration;
|
|
2
|
-
use temporal_client::
|
|
2
|
+
use temporal_client::WorkflowClientTrait;
|
|
3
3
|
use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
|
|
4
4
|
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowExecutionStatus;
|
|
5
5
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
@@ -24,22 +24,14 @@ async fn cancel_during_timer() {
|
|
|
24
24
|
let mut worker = starter.worker().await;
|
|
25
25
|
let client = starter.get_client().await;
|
|
26
26
|
worker.register_wf(wf_name.to_string(), cancelled_wf);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.submit_wf(
|
|
30
|
-
wf_name.to_owned(),
|
|
31
|
-
wf_name.to_owned(),
|
|
32
|
-
vec![],
|
|
33
|
-
WorkflowOptions::default(),
|
|
34
|
-
)
|
|
35
|
-
.await
|
|
36
|
-
.unwrap();
|
|
27
|
+
starter.start_with_worker(wf_name, &mut worker).await;
|
|
28
|
+
let wf_id = starter.get_task_queue().to_string();
|
|
37
29
|
|
|
38
30
|
let canceller = async {
|
|
39
31
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
40
32
|
// Cancel the workflow externally
|
|
41
33
|
client
|
|
42
|
-
.cancel_workflow_execution(
|
|
34
|
+
.cancel_workflow_execution(wf_id.clone(), None, "Dieee".to_string(), None)
|
|
43
35
|
.await
|
|
44
36
|
.unwrap();
|
|
45
37
|
};
|
|
@@ -47,7 +39,7 @@ async fn cancel_during_timer() {
|
|
|
47
39
|
let (_, res) = tokio::join!(canceller, worker.run_until_done());
|
|
48
40
|
res.unwrap();
|
|
49
41
|
let desc = client
|
|
50
|
-
.describe_workflow_execution(
|
|
42
|
+
.describe_workflow_execution(wf_id, None)
|
|
51
43
|
.await
|
|
52
44
|
.unwrap();
|
|
53
45
|
|
|
@@ -44,7 +44,7 @@ async fn continue_as_new_multiple_concurrent() {
|
|
|
44
44
|
let mut worker = starter.worker().await;
|
|
45
45
|
worker.register_wf(wf_name.to_string(), continue_as_new_wf);
|
|
46
46
|
|
|
47
|
-
let wf_names = (1..=20).map(|i| format!("{}-{}"
|
|
47
|
+
let wf_names = (1..=20).map(|i| format!("{wf_name}-{i}"));
|
|
48
48
|
for name in wf_names.clone() {
|
|
49
49
|
worker
|
|
50
50
|
.submit_wf(
|
|
@@ -2,7 +2,7 @@ use std::{
|
|
|
2
2
|
sync::atomic::{AtomicUsize, Ordering},
|
|
3
3
|
time::Duration,
|
|
4
4
|
};
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
use temporal_sdk::{ActivityOptions, WfContext, WorkflowResult};
|
|
7
7
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
8
8
|
|
|
@@ -39,15 +39,7 @@ async fn test_determinism_error_then_recovers() {
|
|
|
39
39
|
let mut worker = starter.worker().await;
|
|
40
40
|
|
|
41
41
|
worker.register_wf(wf_name.to_owned(), timer_wf_nondeterministic);
|
|
42
|
-
worker
|
|
43
|
-
.submit_wf(
|
|
44
|
-
wf_name.to_owned(),
|
|
45
|
-
wf_name.to_owned(),
|
|
46
|
-
vec![],
|
|
47
|
-
WorkflowOptions::default(),
|
|
48
|
-
)
|
|
49
|
-
.await
|
|
50
|
-
.unwrap();
|
|
42
|
+
starter.start_with_worker(wf_name, &mut worker).await;
|
|
51
43
|
worker.run_until_done().await.unwrap();
|
|
52
44
|
// 4 because we still add on the 3rd and final attempt
|
|
53
45
|
assert_eq!(RUN_CT.load(Ordering::Relaxed), 4);
|