@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
|
@@ -11,14 +11,17 @@ use anyhow::anyhow;
|
|
|
11
11
|
use futures::{future::join_all, FutureExt};
|
|
12
12
|
use std::{
|
|
13
13
|
collections::HashMap,
|
|
14
|
+
ops::Sub,
|
|
14
15
|
sync::{
|
|
15
16
|
atomic::{AtomicUsize, Ordering},
|
|
16
17
|
Arc,
|
|
17
18
|
},
|
|
18
|
-
time::Duration,
|
|
19
|
+
time::{Duration, SystemTime},
|
|
19
20
|
};
|
|
20
21
|
use temporal_client::WorkflowOptions;
|
|
21
|
-
use temporal_sdk::{
|
|
22
|
+
use temporal_sdk::{
|
|
23
|
+
ActContext, ActivityCancelledError, LocalActivityOptions, WfContext, WorkflowResult,
|
|
24
|
+
};
|
|
22
25
|
use temporal_sdk_core_api::Worker;
|
|
23
26
|
use temporal_sdk_core_protos::{
|
|
24
27
|
coresdk::{
|
|
@@ -29,7 +32,9 @@ use temporal_sdk_core_protos::{
|
|
|
29
32
|
ActivityTaskCompletion, AsJsonPayloadExt,
|
|
30
33
|
},
|
|
31
34
|
temporal::api::{
|
|
32
|
-
common::v1::RetryPolicy,
|
|
35
|
+
common::v1::RetryPolicy,
|
|
36
|
+
enums::v1::{EventType, TimeoutType, WorkflowTaskFailedCause},
|
|
37
|
+
failure::v1::Failure,
|
|
33
38
|
query::v1::WorkflowQuery,
|
|
34
39
|
},
|
|
35
40
|
};
|
|
@@ -106,7 +111,7 @@ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
106
111
|
.map(|i| {
|
|
107
112
|
ctx.local_activity(LocalActivityOptions {
|
|
108
113
|
activity_type: "echo".to_string(),
|
|
109
|
-
input: format!("Hi {}"
|
|
114
|
+
input: format!("Hi {i}")
|
|
110
115
|
.as_json_payload()
|
|
111
116
|
.expect("serializes fine"),
|
|
112
117
|
..Default::default()
|
|
@@ -120,6 +125,7 @@ pub async fn local_act_fanout_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
120
125
|
|
|
121
126
|
#[tokio::test]
|
|
122
127
|
async fn local_act_many_concurrent() {
|
|
128
|
+
crate::telemetry::test_telem_console();
|
|
123
129
|
let mut t = TestHistoryBuilder::default();
|
|
124
130
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
125
131
|
t.add_full_wf_task();
|
|
@@ -164,12 +170,7 @@ async fn local_act_many_concurrent() {
|
|
|
164
170
|
async fn local_act_heartbeat(#[case] shutdown_middle: bool) {
|
|
165
171
|
let mut t = TestHistoryBuilder::default();
|
|
166
172
|
let wft_timeout = Duration::from_millis(200);
|
|
167
|
-
|
|
168
|
-
wes_short_wft_timeout.workflow_task_timeout = Some(wft_timeout.try_into().unwrap());
|
|
169
|
-
t.add(
|
|
170
|
-
EventType::WorkflowExecutionStarted,
|
|
171
|
-
wes_short_wft_timeout.into(),
|
|
172
|
-
);
|
|
173
|
+
t.add_wfe_started_with_wft_timeout(wft_timeout);
|
|
173
174
|
t.add_full_wf_task();
|
|
174
175
|
// Task created by WFT heartbeat
|
|
175
176
|
t.add_full_wf_task();
|
|
@@ -367,7 +368,7 @@ async fn local_act_null_result() {
|
|
|
367
368
|
let mut t = TestHistoryBuilder::default();
|
|
368
369
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
369
370
|
t.add_full_wf_task();
|
|
370
|
-
t.add_local_activity_marker(1, "1", None, None,
|
|
371
|
+
t.add_local_activity_marker(1, "1", None, None, |_| {});
|
|
371
372
|
t.add_workflow_execution_completed();
|
|
372
373
|
|
|
373
374
|
let wf_id = "fakeid";
|
|
@@ -408,7 +409,7 @@ async fn local_act_command_immediately_follows_la_marker() {
|
|
|
408
409
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
409
410
|
t.add_full_wf_task();
|
|
410
411
|
t.add_full_wf_task();
|
|
411
|
-
t.
|
|
412
|
+
t.add_local_activity_result_marker(1, "1", "done".into());
|
|
412
413
|
t.add_get_event_id(EventType::TimerStarted, None);
|
|
413
414
|
t.add_full_wf_task();
|
|
414
415
|
|
|
@@ -448,16 +449,11 @@ async fn local_act_command_immediately_follows_la_marker() {
|
|
|
448
449
|
async fn query_during_wft_heartbeat_doesnt_accidentally_fail_to_continue_heartbeat() {
|
|
449
450
|
let wfid = "fake_wf_id";
|
|
450
451
|
let mut t = TestHistoryBuilder::default();
|
|
451
|
-
|
|
452
|
-
wes_short_wft_timeout.workflow_task_timeout = Some(prost_dur!(from_millis(200)));
|
|
453
|
-
t.add(
|
|
454
|
-
EventType::WorkflowExecutionStarted,
|
|
455
|
-
wes_short_wft_timeout.into(),
|
|
456
|
-
);
|
|
452
|
+
t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
|
|
457
453
|
t.add_full_wf_task();
|
|
458
454
|
// get query here
|
|
459
455
|
t.add_full_wf_task();
|
|
460
|
-
t.
|
|
456
|
+
t.add_local_activity_result_marker(1, "1", "done".into());
|
|
461
457
|
t.add_workflow_execution_completed();
|
|
462
458
|
|
|
463
459
|
let query_with_hist_task = {
|
|
@@ -582,7 +578,7 @@ async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_quer
|
|
|
582
578
|
// nonlegacy query got here & LA started here
|
|
583
579
|
t.add_full_wf_task();
|
|
584
580
|
// legacy query got here, at the same time that the LA is resolved
|
|
585
|
-
t.
|
|
581
|
+
t.add_local_activity_result_marker(1, "1", "whatever".into());
|
|
586
582
|
t.add_workflow_execution_completed();
|
|
587
583
|
|
|
588
584
|
let barr = Arc::new(Barrier::new(2));
|
|
@@ -618,8 +614,12 @@ async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_quer
|
|
|
618
614
|
2,
|
|
619
615
|
),
|
|
620
616
|
);
|
|
621
|
-
// Strip history
|
|
622
|
-
|
|
617
|
+
// Strip beginning of history so the only events are WFT sched/started, we need to look
|
|
618
|
+
// like we hit the cache
|
|
619
|
+
{
|
|
620
|
+
let h = pr.history.as_mut().unwrap();
|
|
621
|
+
h.events = h.events.split_off(6);
|
|
622
|
+
}
|
|
623
623
|
// In the nonsense server response case, we attach a legacy query, otherwise this
|
|
624
624
|
// response looks like a normal response to a forced WFT heartbeat.
|
|
625
625
|
if impossible_query_in_task {
|
|
@@ -735,3 +735,244 @@ async fn la_resolve_during_legacy_query_does_not_combine(#[case] impossible_quer
|
|
|
735
735
|
tokio::join!(wf_fut, act_fut);
|
|
736
736
|
core.shutdown().await;
|
|
737
737
|
}
|
|
738
|
+
|
|
739
|
+
#[tokio::test]
|
|
740
|
+
async fn test_schedule_to_start_timeout() {
|
|
741
|
+
let mut t = TestHistoryBuilder::default();
|
|
742
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
743
|
+
t.add_full_wf_task();
|
|
744
|
+
|
|
745
|
+
let wf_id = "fakeid";
|
|
746
|
+
let mock = mock_workflow_client();
|
|
747
|
+
let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::ToTaskNum(1)], mock);
|
|
748
|
+
let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
|
|
749
|
+
|
|
750
|
+
worker.register_wf(
|
|
751
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
752
|
+
|ctx: WfContext| async move {
|
|
753
|
+
let la_res = ctx
|
|
754
|
+
.local_activity(LocalActivityOptions {
|
|
755
|
+
activity_type: "echo".to_string(),
|
|
756
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
757
|
+
// Impossibly small timeout so we timeout in the queue
|
|
758
|
+
schedule_to_start_timeout: prost_dur!(from_nanos(1)),
|
|
759
|
+
..Default::default()
|
|
760
|
+
})
|
|
761
|
+
.await;
|
|
762
|
+
assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToStart));
|
|
763
|
+
Ok(().into())
|
|
764
|
+
},
|
|
765
|
+
);
|
|
766
|
+
worker.register_activity(
|
|
767
|
+
"echo",
|
|
768
|
+
move |_ctx: ActContext, _: String| async move { Ok(()) },
|
|
769
|
+
);
|
|
770
|
+
worker
|
|
771
|
+
.submit_wf(
|
|
772
|
+
wf_id.to_owned(),
|
|
773
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
774
|
+
vec![],
|
|
775
|
+
WorkflowOptions::default(),
|
|
776
|
+
)
|
|
777
|
+
.await
|
|
778
|
+
.unwrap();
|
|
779
|
+
worker.run_until_done().await.unwrap();
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
#[rstest::rstest]
|
|
783
|
+
#[case::sched_to_start(true)]
|
|
784
|
+
#[case::sched_to_close(false)]
|
|
785
|
+
#[tokio::test]
|
|
786
|
+
async fn test_schedule_to_start_timeout_not_based_on_original_time(
|
|
787
|
+
#[case] is_sched_to_start: bool,
|
|
788
|
+
) {
|
|
789
|
+
// We used to carry over the schedule time of LAs from the "original" schedule time if these LAs
|
|
790
|
+
// created newly after backing off across a timer. That was a mistake, since schedule-to-start
|
|
791
|
+
// timeouts should apply to when the new attempt was scheduled. This test verifies:
|
|
792
|
+
// * we don't time out on s-t-s timeouts because of that, when the param is true.
|
|
793
|
+
// * we do properly time out on s-t-c timeouts when the param is false
|
|
794
|
+
|
|
795
|
+
let mut t = TestHistoryBuilder::default();
|
|
796
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
797
|
+
t.add_full_wf_task();
|
|
798
|
+
let orig_sched = SystemTime::now().sub(Duration::from_secs(60 * 20));
|
|
799
|
+
t.add_local_activity_marker(
|
|
800
|
+
1,
|
|
801
|
+
"1",
|
|
802
|
+
None,
|
|
803
|
+
Some(Failure::application_failure("la failed".to_string(), false)),
|
|
804
|
+
|deets| {
|
|
805
|
+
// Really old schedule time, which should _not_ count against schedule_to_start
|
|
806
|
+
deets.original_schedule_time = Some(orig_sched.into());
|
|
807
|
+
// Backoff value must be present since we're simulating timer backoff
|
|
808
|
+
deets.backoff = Some(prost_dur!(from_secs(100)));
|
|
809
|
+
},
|
|
810
|
+
);
|
|
811
|
+
let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
812
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
813
|
+
t.add_workflow_task_scheduled_and_started();
|
|
814
|
+
|
|
815
|
+
let wf_id = "fakeid";
|
|
816
|
+
let mock = mock_workflow_client();
|
|
817
|
+
let mh = MockPollCfg::from_resp_batches(wf_id, t, [ResponseType::AllHistory], mock);
|
|
818
|
+
let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
|
|
819
|
+
|
|
820
|
+
let schedule_to_close_timeout = Some(if is_sched_to_start {
|
|
821
|
+
// This 60 minute timeout will not have elapsed according to the original
|
|
822
|
+
// schedule time in the history.
|
|
823
|
+
Duration::from_secs(60 * 60)
|
|
824
|
+
} else {
|
|
825
|
+
// This 10 minute timeout will have already elapsed
|
|
826
|
+
Duration::from_secs(10 * 60)
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
worker.register_wf(
|
|
830
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
831
|
+
move |ctx: WfContext| async move {
|
|
832
|
+
let la_res = ctx
|
|
833
|
+
.local_activity(LocalActivityOptions {
|
|
834
|
+
activity_type: "echo".to_string(),
|
|
835
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
836
|
+
retry_policy: RetryPolicy {
|
|
837
|
+
initial_interval: Some(prost_dur!(from_millis(50))),
|
|
838
|
+
backoff_coefficient: 1.2,
|
|
839
|
+
maximum_interval: None,
|
|
840
|
+
maximum_attempts: 5,
|
|
841
|
+
non_retryable_error_types: vec![],
|
|
842
|
+
},
|
|
843
|
+
schedule_to_start_timeout: Some(Duration::from_secs(60)),
|
|
844
|
+
schedule_to_close_timeout,
|
|
845
|
+
..Default::default()
|
|
846
|
+
})
|
|
847
|
+
.await;
|
|
848
|
+
if is_sched_to_start {
|
|
849
|
+
assert!(la_res.completed_ok());
|
|
850
|
+
} else {
|
|
851
|
+
assert_eq!(la_res.timed_out(), Some(TimeoutType::ScheduleToClose));
|
|
852
|
+
}
|
|
853
|
+
Ok(().into())
|
|
854
|
+
},
|
|
855
|
+
);
|
|
856
|
+
worker.register_activity(
|
|
857
|
+
"echo",
|
|
858
|
+
move |_ctx: ActContext, _: String| async move { Ok(()) },
|
|
859
|
+
);
|
|
860
|
+
worker
|
|
861
|
+
.submit_wf(
|
|
862
|
+
wf_id.to_owned(),
|
|
863
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
864
|
+
vec![],
|
|
865
|
+
WorkflowOptions::default(),
|
|
866
|
+
)
|
|
867
|
+
.await
|
|
868
|
+
.unwrap();
|
|
869
|
+
worker.run_until_done().await.unwrap();
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
#[tokio::test]
|
|
873
|
+
async fn wft_failure_cancels_running_las() {
|
|
874
|
+
let mut t = TestHistoryBuilder::default();
|
|
875
|
+
t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
|
|
876
|
+
t.add_full_wf_task();
|
|
877
|
+
let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
878
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
879
|
+
t.add_workflow_task_scheduled_and_started();
|
|
880
|
+
|
|
881
|
+
let wf_id = "fakeid";
|
|
882
|
+
let mock = mock_workflow_client();
|
|
883
|
+
let mut mh = MockPollCfg::from_resp_batches(wf_id, t, [1, 2], mock);
|
|
884
|
+
mh.num_expected_fails = 1;
|
|
885
|
+
let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
|
|
886
|
+
|
|
887
|
+
worker.register_wf(
|
|
888
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
889
|
+
|ctx: WfContext| async move {
|
|
890
|
+
let la_handle = ctx.local_activity(LocalActivityOptions {
|
|
891
|
+
activity_type: "echo".to_string(),
|
|
892
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
893
|
+
..Default::default()
|
|
894
|
+
});
|
|
895
|
+
tokio::join!(
|
|
896
|
+
async {
|
|
897
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
898
|
+
panic!("ahhh I'm failing wft")
|
|
899
|
+
},
|
|
900
|
+
la_handle
|
|
901
|
+
);
|
|
902
|
+
Ok(().into())
|
|
903
|
+
},
|
|
904
|
+
);
|
|
905
|
+
worker.register_activity("echo", move |ctx: ActContext, _: String| async move {
|
|
906
|
+
let res = tokio::time::timeout(Duration::from_millis(500), ctx.cancelled()).await;
|
|
907
|
+
if res.is_err() {
|
|
908
|
+
panic!("Activity must be cancelled!!!!");
|
|
909
|
+
}
|
|
910
|
+
Result::<(), _>::Err(ActivityCancelledError::default().into())
|
|
911
|
+
});
|
|
912
|
+
worker
|
|
913
|
+
.submit_wf(
|
|
914
|
+
wf_id.to_owned(),
|
|
915
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
916
|
+
vec![],
|
|
917
|
+
WorkflowOptions::default(),
|
|
918
|
+
)
|
|
919
|
+
.await
|
|
920
|
+
.unwrap();
|
|
921
|
+
worker.run_until_done().await.unwrap();
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
#[tokio::test]
|
|
925
|
+
async fn resolved_las_not_recorded_if_wft_fails_many_times() {
|
|
926
|
+
// We shouldn't record any LA results if the workflow activation is repeatedly failing. There
|
|
927
|
+
// was an issue that, because we stop reporting WFT failures after 2 tries, this meant the WFT
|
|
928
|
+
// was not marked as "completed" and the WFT could accidentally be replied to with LA results.
|
|
929
|
+
let mut t = TestHistoryBuilder::default();
|
|
930
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
931
|
+
t.add_workflow_task_scheduled_and_started();
|
|
932
|
+
t.add_workflow_task_failed_with_failure(
|
|
933
|
+
WorkflowTaskFailedCause::Unspecified,
|
|
934
|
+
Default::default(),
|
|
935
|
+
);
|
|
936
|
+
t.add_workflow_task_scheduled_and_started();
|
|
937
|
+
|
|
938
|
+
let wf_id = "fakeid";
|
|
939
|
+
let mock = mock_workflow_client();
|
|
940
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
941
|
+
wf_id,
|
|
942
|
+
t,
|
|
943
|
+
[1.into(), ResponseType::AllHistory, ResponseType::AllHistory],
|
|
944
|
+
mock,
|
|
945
|
+
);
|
|
946
|
+
mh.num_expected_fails = 2;
|
|
947
|
+
mh.completion_asserts = Some(Box::new(|_| {
|
|
948
|
+
panic!("should never successfully complete a WFT");
|
|
949
|
+
}));
|
|
950
|
+
let mut worker = mock_sdk_cfg(mh, |w| w.max_cached_workflows = 1);
|
|
951
|
+
|
|
952
|
+
worker.register_wf(
|
|
953
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
954
|
+
|ctx: WfContext| async move {
|
|
955
|
+
ctx.local_activity(LocalActivityOptions {
|
|
956
|
+
activity_type: "echo".to_string(),
|
|
957
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
958
|
+
..Default::default()
|
|
959
|
+
})
|
|
960
|
+
.await;
|
|
961
|
+
panic!("Oh nooooo")
|
|
962
|
+
},
|
|
963
|
+
);
|
|
964
|
+
worker.register_activity(
|
|
965
|
+
"echo",
|
|
966
|
+
move |_: ActContext, _: String| async move { Ok(()) },
|
|
967
|
+
);
|
|
968
|
+
worker
|
|
969
|
+
.submit_wf(
|
|
970
|
+
wf_id.to_owned(),
|
|
971
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
972
|
+
vec![],
|
|
973
|
+
WorkflowOptions::default(),
|
|
974
|
+
)
|
|
975
|
+
.await
|
|
976
|
+
.unwrap();
|
|
977
|
+
worker.run_until_done().await.unwrap();
|
|
978
|
+
}
|
|
@@ -162,7 +162,7 @@ async fn new_queries(#[case] num_queries: usize) {
|
|
|
162
162
|
pr.queries = HashMap::new();
|
|
163
163
|
for i in 1..=num_queries {
|
|
164
164
|
pr.queries.insert(
|
|
165
|
-
format!("q{}"
|
|
165
|
+
format!("q{i}"),
|
|
166
166
|
WorkflowQuery {
|
|
167
167
|
query_type: "query-type".to_string(),
|
|
168
168
|
query_args: Some(b"hi".into()),
|
|
@@ -206,7 +206,7 @@ async fn new_queries(#[case] num_queries: usize) {
|
|
|
206
206
|
let mut qresults: Vec<_> = (1..=num_queries)
|
|
207
207
|
.map(|i| {
|
|
208
208
|
QueryResult {
|
|
209
|
-
query_id: format!("q{}"
|
|
209
|
+
query_id: format!("q{i}"),
|
|
210
210
|
variant: Some(
|
|
211
211
|
QuerySuccess {
|
|
212
212
|
response: Some(query_resp.into()),
|
|
@@ -892,7 +892,7 @@ async fn max_wft_respected() {
|
|
|
892
892
|
let total_wfs = 100;
|
|
893
893
|
let wf_ids: Vec<_> = (0..total_wfs)
|
|
894
894
|
.into_iter()
|
|
895
|
-
.map(|i| format!("fake-wf-{}"
|
|
895
|
+
.map(|i| format!("fake-wf-{i}"))
|
|
896
896
|
.collect();
|
|
897
897
|
let hists = wf_ids.iter().map(|wf_id| {
|
|
898
898
|
let hist = canned_histories::single_timer("1");
|
|
@@ -1022,7 +1022,7 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
|
|
|
1022
1022
|
async fn lots_of_workflows() {
|
|
1023
1023
|
let total_wfs = 500;
|
|
1024
1024
|
let hists = (0..total_wfs).into_iter().map(|i| {
|
|
1025
|
-
let wf_id = format!("fake-wf-{}"
|
|
1025
|
+
let wf_id = format!("fake-wf-{i}");
|
|
1026
1026
|
let hist = canned_histories::single_timer("1");
|
|
1027
1027
|
FakeWfResponses {
|
|
1028
1028
|
wf_id,
|
|
@@ -1546,9 +1546,8 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1546
1546
|
))
|
|
1547
1547
|
.await
|
|
1548
1548
|
.unwrap();
|
|
1549
|
-
assert_eq!(worker.available_wft_permits().await, 2);
|
|
1550
|
-
|
|
1551
1549
|
worker.shutdown().await;
|
|
1550
|
+
assert_eq!(worker.available_wft_permits().await, 2);
|
|
1552
1551
|
}
|
|
1553
1552
|
|
|
1554
1553
|
#[tokio::test]
|
|
@@ -1574,6 +1573,8 @@ async fn cache_miss_will_fetch_history() {
|
|
|
1574
1573
|
let mut mock = build_mock_pollers(mh);
|
|
1575
1574
|
mock.worker_cfg(|cfg| {
|
|
1576
1575
|
cfg.max_cached_workflows = 1;
|
|
1576
|
+
// Also verifies tying the WFT permit to the fetch request doesn't get us stuck
|
|
1577
|
+
cfg.max_outstanding_workflow_tasks = 1;
|
|
1577
1578
|
});
|
|
1578
1579
|
let worker = mock_worker(mock);
|
|
1579
1580
|
|
|
@@ -1655,6 +1656,55 @@ async fn tasks_from_completion_are_delivered() {
|
|
|
1655
1656
|
let complete_resp = RespondWorkflowTaskCompletedResponse {
|
|
1656
1657
|
workflow_task: Some(hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp),
|
|
1657
1658
|
activity_tasks: vec![],
|
|
1659
|
+
reset_history_event_id: 0,
|
|
1660
|
+
};
|
|
1661
|
+
mock.expect_complete_workflow_task()
|
|
1662
|
+
.times(1)
|
|
1663
|
+
.returning(move |_| Ok(complete_resp.clone()));
|
|
1664
|
+
mock.expect_complete_workflow_task()
|
|
1665
|
+
.times(1)
|
|
1666
|
+
.returning(|_| Ok(Default::default()));
|
|
1667
|
+
let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
|
|
1668
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
|
|
1669
|
+
let core = mock_worker(mock);
|
|
1670
|
+
|
|
1671
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
1672
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
1673
|
+
.await
|
|
1674
|
+
.unwrap();
|
|
1675
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
1676
|
+
assert_matches!(
|
|
1677
|
+
wf_task.jobs.as_slice(),
|
|
1678
|
+
[WorkflowActivationJob {
|
|
1679
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
1680
|
+
},]
|
|
1681
|
+
);
|
|
1682
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
1683
|
+
wf_task.run_id,
|
|
1684
|
+
vec![CompleteWorkflowExecution { result: None }.into()],
|
|
1685
|
+
))
|
|
1686
|
+
.await
|
|
1687
|
+
.unwrap();
|
|
1688
|
+
core.shutdown().await;
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
#[tokio::test]
|
|
1692
|
+
async fn pagination_works_with_tasks_from_completion() {
|
|
1693
|
+
let wfid = "fake_wf_id";
|
|
1694
|
+
let mut t = TestHistoryBuilder::default();
|
|
1695
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
1696
|
+
t.add_full_wf_task();
|
|
1697
|
+
t.add_we_signaled("sig", vec![]);
|
|
1698
|
+
t.add_full_wf_task();
|
|
1699
|
+
t.add_workflow_execution_completed();
|
|
1700
|
+
let get_exec_resp: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
|
|
1701
|
+
|
|
1702
|
+
let mut mock = mock_workflow_client();
|
|
1703
|
+
let mut needs_pag_resp = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2)).resp;
|
|
1704
|
+
needs_pag_resp.next_page_token = vec![1];
|
|
1705
|
+
let complete_resp = RespondWorkflowTaskCompletedResponse {
|
|
1706
|
+
workflow_task: Some(needs_pag_resp),
|
|
1707
|
+
..Default::default()
|
|
1658
1708
|
};
|
|
1659
1709
|
mock.expect_complete_workflow_task()
|
|
1660
1710
|
.times(1)
|
|
@@ -1662,6 +1712,9 @@ async fn tasks_from_completion_are_delivered() {
|
|
|
1662
1712
|
mock.expect_complete_workflow_task()
|
|
1663
1713
|
.times(1)
|
|
1664
1714
|
.returning(|_| Ok(Default::default()));
|
|
1715
|
+
mock.expect_get_workflow_execution_history()
|
|
1716
|
+
.returning(move |_, _, _| Ok(get_exec_resp.clone()))
|
|
1717
|
+
.times(1);
|
|
1665
1718
|
let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
|
|
1666
1719
|
mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
|
|
1667
1720
|
let core = mock_worker(mock);
|
|
@@ -1691,7 +1744,7 @@ async fn poll_faster_than_complete_wont_overflow_cache() {
|
|
|
1691
1744
|
// Make workflow tasks for 5 different runs
|
|
1692
1745
|
let tasks: Vec<_> = (1..=5)
|
|
1693
1746
|
.map(|i| FakeWfResponses {
|
|
1694
|
-
wf_id: format!("wf-{}"
|
|
1747
|
+
wf_id: format!("wf-{i}"),
|
|
1695
1748
|
hist: canned_histories::single_timer("1"),
|
|
1696
1749
|
response_batches: vec![ResponseType::ToTaskNum(1)],
|
|
1697
1750
|
})
|
|
@@ -2087,3 +2140,194 @@ async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
|
|
|
2087
2140
|
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2088
2141
|
);
|
|
2089
2142
|
}
|
|
2143
|
+
|
|
2144
|
+
#[tokio::test]
|
|
2145
|
+
async fn fetching_to_continue_replay_works() {
|
|
2146
|
+
let mut mock_client = mock_workflow_client();
|
|
2147
|
+
let mut t = TestHistoryBuilder::default();
|
|
2148
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2149
|
+
t.add_full_wf_task();
|
|
2150
|
+
t.add_full_wf_task(); // ends 7
|
|
2151
|
+
let mut need_fetch_resp =
|
|
2152
|
+
hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
|
|
2153
|
+
need_fetch_resp.next_page_token = vec![1];
|
|
2154
|
+
|
|
2155
|
+
t.add_full_wf_task();
|
|
2156
|
+
t.add_we_signaled("hi", vec![]); // Need to make there be two complete WFTs
|
|
2157
|
+
t.add_full_wf_task(); // end 14
|
|
2158
|
+
let mut fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2159
|
+
t.get_full_history_info().unwrap().into();
|
|
2160
|
+
// Should only contain events after 7
|
|
2161
|
+
if let Some(ref mut h) = fetch_resp.history {
|
|
2162
|
+
h.events.retain(|e| e.event_id >= 8);
|
|
2163
|
+
}
|
|
2164
|
+
// And indicate that even *more* needs to be fetched after this, so we see a request for the
|
|
2165
|
+
// next page happen.
|
|
2166
|
+
fetch_resp.next_page_token = vec![2];
|
|
2167
|
+
|
|
2168
|
+
let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
2169
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
2170
|
+
t.add_full_wf_task();
|
|
2171
|
+
let mut final_fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2172
|
+
t.get_full_history_info().unwrap().into();
|
|
2173
|
+
// Should have only the final event
|
|
2174
|
+
if let Some(ref mut h) = final_fetch_resp.history {
|
|
2175
|
+
h.events.retain(|e| e.event_id >= 15);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
let tasks = vec![
|
|
2179
|
+
ResponseType::ToTaskNum(1),
|
|
2180
|
+
ResponseType::Raw(need_fetch_resp),
|
|
2181
|
+
];
|
|
2182
|
+
mock_client
|
|
2183
|
+
.expect_get_workflow_execution_history()
|
|
2184
|
+
.returning(move |_, _, _| Ok(fetch_resp.clone()))
|
|
2185
|
+
.times(1);
|
|
2186
|
+
mock_client
|
|
2187
|
+
.expect_get_workflow_execution_history()
|
|
2188
|
+
.returning(move |_, _, _| Ok(final_fetch_resp.clone()))
|
|
2189
|
+
.times(1);
|
|
2190
|
+
let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
|
|
2191
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
2192
|
+
let core = mock_worker(mock);
|
|
2193
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2194
|
+
assert_matches!(
|
|
2195
|
+
act.jobs[0].variant,
|
|
2196
|
+
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2197
|
+
);
|
|
2198
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
2199
|
+
.await
|
|
2200
|
+
.unwrap();
|
|
2201
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2202
|
+
assert_matches!(
|
|
2203
|
+
act.jobs.as_slice(),
|
|
2204
|
+
[WorkflowActivationJob {
|
|
2205
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
2206
|
+
}]
|
|
2207
|
+
);
|
|
2208
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
2209
|
+
act.run_id,
|
|
2210
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
2211
|
+
))
|
|
2212
|
+
.await
|
|
2213
|
+
.unwrap();
|
|
2214
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2215
|
+
assert_matches!(
|
|
2216
|
+
act.jobs.as_slice(),
|
|
2217
|
+
[WorkflowActivationJob {
|
|
2218
|
+
variant: Some(workflow_activation_job::Variant::FireTimer(_)),
|
|
2219
|
+
}]
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
#[tokio::test]
|
|
2224
|
+
async fn fetching_error_evicts_wf() {
|
|
2225
|
+
let mut mock_client = mock_workflow_client();
|
|
2226
|
+
let mut t = TestHistoryBuilder::default();
|
|
2227
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2228
|
+
t.add_workflow_task_scheduled_and_started();
|
|
2229
|
+
t.add_workflow_task_completed();
|
|
2230
|
+
let mut need_fetch_resp =
|
|
2231
|
+
hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
|
|
2232
|
+
need_fetch_resp.next_page_token = vec![1];
|
|
2233
|
+
let tasks = vec![
|
|
2234
|
+
ResponseType::ToTaskNum(1),
|
|
2235
|
+
ResponseType::Raw(need_fetch_resp),
|
|
2236
|
+
];
|
|
2237
|
+
mock_client
|
|
2238
|
+
.expect_get_workflow_execution_history()
|
|
2239
|
+
.returning(move |_, _, _| Err(tonic::Status::not_found("Ahh broken")))
|
|
2240
|
+
.times(1);
|
|
2241
|
+
let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
|
|
2242
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
2243
|
+
let core = mock_worker(mock);
|
|
2244
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2245
|
+
assert_matches!(
|
|
2246
|
+
act.jobs[0].variant,
|
|
2247
|
+
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2248
|
+
);
|
|
2249
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
2250
|
+
.await
|
|
2251
|
+
.unwrap();
|
|
2252
|
+
let evict_act = core.poll_workflow_activation().await.unwrap();
|
|
2253
|
+
assert_matches!(
|
|
2254
|
+
evict_act.jobs.as_slice(),
|
|
2255
|
+
[WorkflowActivationJob {
|
|
2256
|
+
variant: Some(workflow_activation_job::Variant::RemoveFromCache(r)),
|
|
2257
|
+
}] => r.message.contains("Fetching history failed")
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
/// This test verifies that if we fail to fetch a page during a completion, that we don't get stuck
|
|
2262
|
+
/// in the complete waiting for the completion to finish.
|
|
2263
|
+
#[tokio::test]
|
|
2264
|
+
async fn ensure_fetching_fail_during_complete_sends_task_failure() {
|
|
2265
|
+
let wfid = "fake_wf_id";
|
|
2266
|
+
let mut t = TestHistoryBuilder::default();
|
|
2267
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2268
|
+
t.add_full_wf_task(); // started 3
|
|
2269
|
+
t.add_we_signaled("sig1", vec![]);
|
|
2270
|
+
t.add_full_wf_task(); // started 7
|
|
2271
|
+
t.add_we_signaled("sig2", vec![]);
|
|
2272
|
+
t.add_full_wf_task(); // started 11
|
|
2273
|
+
t.add_workflow_execution_completed();
|
|
2274
|
+
|
|
2275
|
+
let mut first_poll = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1)).resp;
|
|
2276
|
+
first_poll.next_page_token = vec![1];
|
|
2277
|
+
first_poll.previous_started_event_id = 3;
|
|
2278
|
+
|
|
2279
|
+
let mut next_page: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
|
|
2280
|
+
next_page.next_page_token = vec![2];
|
|
2281
|
+
|
|
2282
|
+
let mut mock = mock_workflow_client();
|
|
2283
|
+
mock.expect_get_workflow_execution_history()
|
|
2284
|
+
.returning(move |_, _, _| {
|
|
2285
|
+
error!("Called fetch!");
|
|
2286
|
+
Ok(next_page.clone())
|
|
2287
|
+
})
|
|
2288
|
+
.times(1);
|
|
2289
|
+
let mut really_empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2290
|
+
t.get_history_info(1).unwrap().into();
|
|
2291
|
+
really_empty_fetch_resp.history = Some(Default::default());
|
|
2292
|
+
mock.expect_get_workflow_execution_history()
|
|
2293
|
+
.returning(move |_, _, _| {
|
|
2294
|
+
error!("Called fetch second time!");
|
|
2295
|
+
Ok(really_empty_fetch_resp.clone())
|
|
2296
|
+
})
|
|
2297
|
+
.times(1);
|
|
2298
|
+
mock.expect_fail_workflow_task()
|
|
2299
|
+
.returning(|_, _, _| Ok(Default::default()))
|
|
2300
|
+
.times(1);
|
|
2301
|
+
|
|
2302
|
+
let mut mock = single_hist_mock_sg(wfid, t, [ResponseType::Raw(first_poll)], mock, true);
|
|
2303
|
+
mock.make_wft_stream_interminable();
|
|
2304
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
|
|
2305
|
+
let core = mock_worker(mock);
|
|
2306
|
+
|
|
2307
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2308
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
2309
|
+
.await
|
|
2310
|
+
.unwrap();
|
|
2311
|
+
|
|
2312
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2313
|
+
assert_matches!(
|
|
2314
|
+
wf_task.jobs.as_slice(),
|
|
2315
|
+
[WorkflowActivationJob {
|
|
2316
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
2317
|
+
},]
|
|
2318
|
+
);
|
|
2319
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
2320
|
+
.await
|
|
2321
|
+
.unwrap();
|
|
2322
|
+
|
|
2323
|
+
// Expect to see eviction b/c of history fetching error here.
|
|
2324
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2325
|
+
assert_matches!(
|
|
2326
|
+
wf_task.jobs.as_slice(),
|
|
2327
|
+
[WorkflowActivationJob {
|
|
2328
|
+
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
2329
|
+
},]
|
|
2330
|
+
);
|
|
2331
|
+
|
|
2332
|
+
core.shutdown().await;
|
|
2333
|
+
}
|