@temporalio/core-bridge 1.5.2 → 1.7.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 +304 -112
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +9 -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/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +2 -4
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +29 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +20 -10
- package/sdk-core/client/src/lib.rs +215 -39
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +4 -4
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +25 -12
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +204 -14
- package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +165 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
- package/sdk-core/core/src/core_tests/queries.rs +34 -16
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
- package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
- package/sdk-core/core/src/internal_flags.rs +155 -0
- package/sdk-core/core/src/lib.rs +16 -9
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +60 -21
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +73 -14
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +379 -129
- package/sdk-core/core/src/worker/activities.rs +350 -175
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +183 -64
- 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 +916 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
- 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 +257 -51
- 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 +310 -150
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
- package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
- package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -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 +117 -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 +469 -718
- package/sdk-core/core-api/Cargo.toml +2 -1
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +19 -9
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +19 -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 +86 -61
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +6 -6
- 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 +7 -26
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -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 -7
- 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 +8 -8
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
- 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 +24 -19
- 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 +49 -26
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
- 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/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
- 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 +64 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +67 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- 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 +5 -4
- package/sdk-core/sdk/src/lib.rs +108 -26
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +16 -15
- 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 +138 -106
- package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
- 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/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +82 -23
- 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} +125 -51
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
- package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
- package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
- package/sdk-core/tests/main.rs +3 -13
- package/sdk-core/tests/runner.rs +75 -36
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- 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
|
@@ -16,11 +16,12 @@ use rstest::{fixture, rstest};
|
|
|
16
16
|
use std::{
|
|
17
17
|
collections::{HashMap, VecDeque},
|
|
18
18
|
sync::{
|
|
19
|
-
atomic::{AtomicU64, Ordering},
|
|
19
|
+
atomic::{AtomicBool, AtomicU64, Ordering},
|
|
20
20
|
Arc,
|
|
21
21
|
},
|
|
22
22
|
time::Duration,
|
|
23
23
|
};
|
|
24
|
+
use temporal_client::WorkflowOptions;
|
|
24
25
|
use temporal_sdk::{ActivityOptions, CancellableFuture, WfContext};
|
|
25
26
|
use temporal_sdk_core_api::{errors::PollWfError, Worker as WorkerTrait};
|
|
26
27
|
use temporal_sdk_core_protos::{
|
|
@@ -33,24 +34,29 @@ use temporal_sdk_core_protos::{
|
|
|
33
34
|
workflow_commands::{
|
|
34
35
|
ActivityCancellationType, CancelTimer, CompleteWorkflowExecution,
|
|
35
36
|
ContinueAsNewWorkflowExecution, FailWorkflowExecution, RequestCancelActivity,
|
|
36
|
-
ScheduleActivity,
|
|
37
|
+
ScheduleActivity, SetPatchMarker,
|
|
37
38
|
},
|
|
38
39
|
workflow_completion::WorkflowActivationCompletion,
|
|
39
40
|
},
|
|
40
|
-
default_wes_attribs,
|
|
41
|
+
default_act_sched, default_wes_attribs,
|
|
41
42
|
temporal::api::{
|
|
42
43
|
command::v1::command::Attributes,
|
|
43
44
|
common::v1::{Payload, RetryPolicy},
|
|
44
45
|
enums::v1::{EventType, WorkflowTaskFailedCause},
|
|
45
46
|
failure::v1::Failure,
|
|
46
|
-
history::v1::{
|
|
47
|
+
history::v1::{
|
|
48
|
+
history_event, TimerFiredEventAttributes,
|
|
49
|
+
WorkflowPropertiesModifiedExternallyEventAttributes,
|
|
50
|
+
},
|
|
47
51
|
workflowservice::v1::{
|
|
48
52
|
GetWorkflowExecutionHistoryResponse, RespondWorkflowTaskCompletedResponse,
|
|
49
53
|
},
|
|
50
54
|
},
|
|
51
|
-
DEFAULT_WORKFLOW_TYPE,
|
|
55
|
+
DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE,
|
|
56
|
+
};
|
|
57
|
+
use temporal_sdk_core_test_utils::{
|
|
58
|
+
fanout_tasks, schedule_activity_cmd, start_timer_cmd, WorkerTestHelpers,
|
|
52
59
|
};
|
|
53
|
-
use temporal_sdk_core_test_utils::{fanout_tasks, start_timer_cmd};
|
|
54
60
|
use tokio::{
|
|
55
61
|
join,
|
|
56
62
|
sync::{Barrier, Semaphore},
|
|
@@ -120,7 +126,7 @@ async fn single_activity_completion(worker: Worker) {
|
|
|
120
126
|
&job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
121
127
|
vec![ScheduleActivity {
|
|
122
128
|
activity_id: "fake_activity".to_string(),
|
|
123
|
-
..
|
|
129
|
+
..default_act_sched()
|
|
124
130
|
}
|
|
125
131
|
.into()],
|
|
126
132
|
),
|
|
@@ -245,7 +251,7 @@ async fn scheduled_activity_cancellation_try_cancel(hist_batches: &'static [usiz
|
|
|
245
251
|
seq: activity_seq,
|
|
246
252
|
activity_id: activity_id.to_string(),
|
|
247
253
|
cancellation_type: ActivityCancellationType::TryCancel as i32,
|
|
248
|
-
..
|
|
254
|
+
..default_act_sched()
|
|
249
255
|
}
|
|
250
256
|
.into()],
|
|
251
257
|
),
|
|
@@ -281,7 +287,7 @@ async fn scheduled_activity_timeout(hist_batches: &'static [usize]) {
|
|
|
281
287
|
vec![ScheduleActivity {
|
|
282
288
|
seq: activity_seq,
|
|
283
289
|
activity_id: activity_id.to_string(),
|
|
284
|
-
..
|
|
290
|
+
..default_act_sched()
|
|
285
291
|
}
|
|
286
292
|
.into()],
|
|
287
293
|
),
|
|
@@ -334,7 +340,7 @@ async fn started_activity_timeout(hist_batches: &'static [usize]) {
|
|
|
334
340
|
vec![ScheduleActivity {
|
|
335
341
|
seq: activity_seq,
|
|
336
342
|
activity_id: activity_seq.to_string(),
|
|
337
|
-
..
|
|
343
|
+
..default_act_sched()
|
|
338
344
|
}
|
|
339
345
|
.into()],
|
|
340
346
|
),
|
|
@@ -389,7 +395,7 @@ async fn cancelled_activity_timeout(hist_batches: &'static [usize]) {
|
|
|
389
395
|
vec![ScheduleActivity {
|
|
390
396
|
seq: activity_seq,
|
|
391
397
|
activity_id: activity_id.to_string(),
|
|
392
|
-
..
|
|
398
|
+
..default_act_sched()
|
|
393
399
|
}
|
|
394
400
|
.into()],
|
|
395
401
|
),
|
|
@@ -457,10 +463,10 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
|
|
|
457
463
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
458
464
|
t.add_full_wf_task();
|
|
459
465
|
let act_scheduled_event_id = t.add_activity_task_scheduled(activity_id);
|
|
460
|
-
let timer_started_event_id = t.
|
|
466
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
461
467
|
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
462
468
|
t.add_full_wf_task();
|
|
463
|
-
let timer_started_event_id = t.
|
|
469
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
464
470
|
let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
|
|
465
471
|
t.add_activity_task_completed(
|
|
466
472
|
act_scheduled_event_id,
|
|
@@ -476,7 +482,7 @@ async fn abandoned_activities_ignore_start_and_complete(hist_batches: &'static [
|
|
|
476
482
|
|
|
477
483
|
worker.register_wf(wf_type.to_owned(), |ctx: WfContext| async move {
|
|
478
484
|
let act_fut = ctx.activity(ActivityOptions {
|
|
479
|
-
activity_type:
|
|
485
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
480
486
|
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
481
487
|
cancellation_type: ActivityCancellationType::Abandon,
|
|
482
488
|
..Default::default()
|
|
@@ -542,7 +548,7 @@ async fn verify_activity_cancellation(
|
|
|
542
548
|
seq: activity_seq,
|
|
543
549
|
activity_id: activity_seq.to_string(),
|
|
544
550
|
cancellation_type: cancel_type as i32,
|
|
545
|
-
..
|
|
551
|
+
..default_act_sched()
|
|
546
552
|
}
|
|
547
553
|
.into()],
|
|
548
554
|
),
|
|
@@ -610,7 +616,7 @@ async fn verify_activity_cancellation_wait_for_cancellation(activity_id: u32, wo
|
|
|
610
616
|
seq: activity_id,
|
|
611
617
|
activity_id: activity_id.to_string(),
|
|
612
618
|
cancellation_type: ActivityCancellationType::WaitCancellationCompleted as i32,
|
|
613
|
-
..
|
|
619
|
+
..default_act_sched()
|
|
614
620
|
}
|
|
615
621
|
.into()],
|
|
616
622
|
),
|
|
@@ -892,7 +898,7 @@ async fn max_wft_respected() {
|
|
|
892
898
|
let total_wfs = 100;
|
|
893
899
|
let wf_ids: Vec<_> = (0..total_wfs)
|
|
894
900
|
.into_iter()
|
|
895
|
-
.map(|i| format!("fake-wf-{}"
|
|
901
|
+
.map(|i| format!("fake-wf-{i}"))
|
|
896
902
|
.collect();
|
|
897
903
|
let hists = wf_ids.iter().map(|wf_id| {
|
|
898
904
|
let hist = canned_histories::single_timer("1");
|
|
@@ -947,7 +953,7 @@ async fn activity_not_canceled_on_replay_repro(hist_batches: &'static [usize]) {
|
|
|
947
953
|
seq: activity_id,
|
|
948
954
|
activity_id: activity_id.to_string(),
|
|
949
955
|
cancellation_type: ActivityCancellationType::TryCancel as i32,
|
|
950
|
-
..
|
|
956
|
+
..default_act_sched()
|
|
951
957
|
}
|
|
952
958
|
.into(),
|
|
953
959
|
start_timer_cmd(1, Duration::from_secs(1)),
|
|
@@ -989,9 +995,9 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
|
|
|
989
995
|
&job_assert!(workflow_activation_job::Variant::StartWorkflow(_)),
|
|
990
996
|
vec![ScheduleActivity {
|
|
991
997
|
seq: activity_id,
|
|
992
|
-
activity_id:
|
|
998
|
+
activity_id: "act-1".to_string(),
|
|
993
999
|
cancellation_type: ActivityCancellationType::TryCancel as i32,
|
|
994
|
-
..
|
|
1000
|
+
..default_act_sched()
|
|
995
1001
|
}
|
|
996
1002
|
.into()],
|
|
997
1003
|
),
|
|
@@ -1022,7 +1028,7 @@ async fn activity_not_canceled_when_also_completed_repro(hist_batches: &'static
|
|
|
1022
1028
|
async fn lots_of_workflows() {
|
|
1023
1029
|
let total_wfs = 500;
|
|
1024
1030
|
let hists = (0..total_wfs).into_iter().map(|i| {
|
|
1025
|
-
let wf_id = format!("fake-wf-{}"
|
|
1031
|
+
let wf_id = format!("fake-wf-{i}");
|
|
1026
1032
|
let hist = canned_histories::single_timer("1");
|
|
1027
1033
|
FakeWfResponses {
|
|
1028
1034
|
wf_id,
|
|
@@ -1092,7 +1098,7 @@ async fn wft_timeout_repro(hist_batches: &'static [usize]) {
|
|
|
1092
1098
|
seq: activity_id,
|
|
1093
1099
|
activity_id: activity_id.to_string(),
|
|
1094
1100
|
cancellation_type: ActivityCancellationType::TryCancel as i32,
|
|
1095
|
-
..
|
|
1101
|
+
..default_act_sched()
|
|
1096
1102
|
}
|
|
1097
1103
|
.into()],
|
|
1098
1104
|
),
|
|
@@ -1225,14 +1231,13 @@ async fn buffered_work_drained_on_shutdown() {
|
|
|
1225
1231
|
let resp_1 = hist_to_poll_resp(&t, wfid.to_owned(), 1.into()).resp;
|
|
1226
1232
|
t.add_workflow_task_timed_out();
|
|
1227
1233
|
t.add_full_wf_task();
|
|
1228
|
-
let timer_started_event_id = t.
|
|
1229
|
-
t.add(
|
|
1230
|
-
|
|
1231
|
-
history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
|
|
1234
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
1235
|
+
t.add(history_event::Attributes::TimerFiredEventAttributes(
|
|
1236
|
+
TimerFiredEventAttributes {
|
|
1232
1237
|
started_event_id: timer_started_event_id,
|
|
1233
1238
|
timer_id: "1".to_string(),
|
|
1234
|
-
}
|
|
1235
|
-
);
|
|
1239
|
+
},
|
|
1240
|
+
));
|
|
1236
1241
|
t.add_full_wf_task();
|
|
1237
1242
|
t.add_workflow_execution_completed();
|
|
1238
1243
|
|
|
@@ -1264,6 +1269,8 @@ async fn buffered_work_drained_on_shutdown() {
|
|
|
1264
1269
|
.unwrap();
|
|
1265
1270
|
};
|
|
1266
1271
|
let complete_first = async move {
|
|
1272
|
+
// If the first complete is sent too fast, we may not have had a chance to buffer work.
|
|
1273
|
+
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
1267
1274
|
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
1268
1275
|
act1.run_id,
|
|
1269
1276
|
start_timer_cmd(1, Duration::from_secs(1)),
|
|
@@ -1272,8 +1279,6 @@ async fn buffered_work_drained_on_shutdown() {
|
|
|
1272
1279
|
.unwrap();
|
|
1273
1280
|
};
|
|
1274
1281
|
join!(poll_fut, complete_first, async {
|
|
1275
|
-
// If the shutdown is sent too too fast, we might not have got a chance to even buffer work
|
|
1276
|
-
tokio::time::sleep(Duration::from_millis(5)).await;
|
|
1277
1282
|
core.shutdown().await;
|
|
1278
1283
|
});
|
|
1279
1284
|
}
|
|
@@ -1303,7 +1308,7 @@ async fn fail_wft_then_recover() {
|
|
|
1303
1308
|
act.run_id.clone(),
|
|
1304
1309
|
vec![ScheduleActivity {
|
|
1305
1310
|
activity_id: "fake_activity".to_string(),
|
|
1306
|
-
..
|
|
1311
|
+
..default_act_sched()
|
|
1307
1312
|
}
|
|
1308
1313
|
.into()],
|
|
1309
1314
|
))
|
|
@@ -1355,12 +1360,17 @@ async fn poll_response_triggers_wf_error() {
|
|
|
1355
1360
|
t.add_full_wf_task();
|
|
1356
1361
|
t.add_workflow_execution_completed();
|
|
1357
1362
|
|
|
1358
|
-
let mh = MockPollCfg::from_resp_batches(
|
|
1363
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
1359
1364
|
"fake_wf_id",
|
|
1360
1365
|
t,
|
|
1361
1366
|
[ResponseType::AllHistory],
|
|
1362
1367
|
mock_workflow_client(),
|
|
1363
1368
|
);
|
|
1369
|
+
// Fail wft will be called when auto-failing.
|
|
1370
|
+
mh.num_expected_fails = 1;
|
|
1371
|
+
mh.expect_fail_wft_matcher = Box::new(move |_, cause, _| {
|
|
1372
|
+
matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
|
|
1373
|
+
});
|
|
1364
1374
|
let mock = build_mock_pollers(mh);
|
|
1365
1375
|
let core = mock_worker(mock);
|
|
1366
1376
|
// Poll for first WFT, which is immediately an eviction
|
|
@@ -1453,7 +1463,7 @@ async fn tries_cancel_of_completed_activity() {
|
|
|
1453
1463
|
ScheduleActivity {
|
|
1454
1464
|
seq: 1,
|
|
1455
1465
|
activity_id: "1".to_string(),
|
|
1456
|
-
..
|
|
1466
|
+
..default_act_sched()
|
|
1457
1467
|
}
|
|
1458
1468
|
.into(),
|
|
1459
1469
|
))
|
|
@@ -1546,9 +1556,8 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1546
1556
|
))
|
|
1547
1557
|
.await
|
|
1548
1558
|
.unwrap();
|
|
1549
|
-
assert_eq!(worker.available_wft_permits().await, 2);
|
|
1550
|
-
|
|
1551
1559
|
worker.shutdown().await;
|
|
1560
|
+
assert_eq!(worker.available_wft_permits().await, 2);
|
|
1552
1561
|
}
|
|
1553
1562
|
|
|
1554
1563
|
#[tokio::test]
|
|
@@ -1574,6 +1583,8 @@ async fn cache_miss_will_fetch_history() {
|
|
|
1574
1583
|
let mut mock = build_mock_pollers(mh);
|
|
1575
1584
|
mock.worker_cfg(|cfg| {
|
|
1576
1585
|
cfg.max_cached_workflows = 1;
|
|
1586
|
+
// Also verifies tying the WFT permit to the fetch request doesn't get us stuck
|
|
1587
|
+
cfg.max_outstanding_workflow_tasks = 1;
|
|
1577
1588
|
});
|
|
1578
1589
|
let worker = mock_worker(mock);
|
|
1579
1590
|
|
|
@@ -1655,6 +1666,7 @@ async fn tasks_from_completion_are_delivered() {
|
|
|
1655
1666
|
let complete_resp = RespondWorkflowTaskCompletedResponse {
|
|
1656
1667
|
workflow_task: Some(hist_to_poll_resp(&t, wfid.to_owned(), 2.into()).resp),
|
|
1657
1668
|
activity_tasks: vec![],
|
|
1669
|
+
reset_history_event_id: 0,
|
|
1658
1670
|
};
|
|
1659
1671
|
mock.expect_complete_workflow_task()
|
|
1660
1672
|
.times(1)
|
|
@@ -1686,12 +1698,63 @@ async fn tasks_from_completion_are_delivered() {
|
|
|
1686
1698
|
core.shutdown().await;
|
|
1687
1699
|
}
|
|
1688
1700
|
|
|
1701
|
+
#[tokio::test]
|
|
1702
|
+
async fn pagination_works_with_tasks_from_completion() {
|
|
1703
|
+
let wfid = "fake_wf_id";
|
|
1704
|
+
let mut t = TestHistoryBuilder::default();
|
|
1705
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
1706
|
+
t.add_full_wf_task();
|
|
1707
|
+
t.add_we_signaled("sig", vec![]);
|
|
1708
|
+
t.add_full_wf_task();
|
|
1709
|
+
t.add_workflow_execution_completed();
|
|
1710
|
+
let get_exec_resp: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
|
|
1711
|
+
|
|
1712
|
+
let mut mock = mock_workflow_client();
|
|
1713
|
+
let mut needs_pag_resp = hist_to_poll_resp(&t, wfid.to_owned(), ResponseType::OneTask(2)).resp;
|
|
1714
|
+
needs_pag_resp.next_page_token = vec![1];
|
|
1715
|
+
let complete_resp = RespondWorkflowTaskCompletedResponse {
|
|
1716
|
+
workflow_task: Some(needs_pag_resp),
|
|
1717
|
+
..Default::default()
|
|
1718
|
+
};
|
|
1719
|
+
mock.expect_complete_workflow_task()
|
|
1720
|
+
.times(1)
|
|
1721
|
+
.returning(move |_| Ok(complete_resp.clone()));
|
|
1722
|
+
mock.expect_complete_workflow_task()
|
|
1723
|
+
.times(1)
|
|
1724
|
+
.returning(|_| Ok(Default::default()));
|
|
1725
|
+
mock.expect_get_workflow_execution_history()
|
|
1726
|
+
.returning(move |_, _, _| Ok(get_exec_resp.clone()))
|
|
1727
|
+
.times(1);
|
|
1728
|
+
let mut mock = single_hist_mock_sg(wfid, t, [1], mock, true);
|
|
1729
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
|
|
1730
|
+
let core = mock_worker(mock);
|
|
1731
|
+
|
|
1732
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
1733
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
1734
|
+
.await
|
|
1735
|
+
.unwrap();
|
|
1736
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
1737
|
+
assert_matches!(
|
|
1738
|
+
wf_task.jobs.as_slice(),
|
|
1739
|
+
[WorkflowActivationJob {
|
|
1740
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
1741
|
+
},]
|
|
1742
|
+
);
|
|
1743
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
1744
|
+
wf_task.run_id,
|
|
1745
|
+
vec![CompleteWorkflowExecution { result: None }.into()],
|
|
1746
|
+
))
|
|
1747
|
+
.await
|
|
1748
|
+
.unwrap();
|
|
1749
|
+
core.shutdown().await;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1689
1752
|
#[tokio::test]
|
|
1690
1753
|
async fn poll_faster_than_complete_wont_overflow_cache() {
|
|
1691
1754
|
// Make workflow tasks for 5 different runs
|
|
1692
1755
|
let tasks: Vec<_> = (1..=5)
|
|
1693
1756
|
.map(|i| FakeWfResponses {
|
|
1694
|
-
wf_id: format!("wf-{}"
|
|
1757
|
+
wf_id: format!("wf-{i}"),
|
|
1695
1758
|
hist: canned_histories::single_timer("1"),
|
|
1696
1759
|
response_batches: vec![ResponseType::ToTaskNum(1)],
|
|
1697
1760
|
})
|
|
@@ -1900,7 +1963,7 @@ async fn autocompletes_wft_no_work() {
|
|
|
1900
1963
|
seq: 1,
|
|
1901
1964
|
activity_id: activity_id.to_string(),
|
|
1902
1965
|
cancellation_type: ActivityCancellationType::Abandon as i32,
|
|
1903
|
-
..
|
|
1966
|
+
..default_act_sched()
|
|
1904
1967
|
}
|
|
1905
1968
|
.into(),
|
|
1906
1969
|
))
|
|
@@ -2013,10 +2076,7 @@ async fn continue_as_new_preserves_some_values() {
|
|
|
2013
2076
|
let mut mock_client = mock_workflow_client();
|
|
2014
2077
|
let hist = {
|
|
2015
2078
|
let mut t = TestHistoryBuilder::default();
|
|
2016
|
-
t.add(
|
|
2017
|
-
EventType::WorkflowExecutionStarted,
|
|
2018
|
-
wes_attrs.clone().into(),
|
|
2019
|
-
);
|
|
2079
|
+
t.add(wes_attrs.clone());
|
|
2020
2080
|
t.add_full_wf_task();
|
|
2021
2081
|
t
|
|
2022
2082
|
};
|
|
@@ -2060,21 +2120,19 @@ async fn continue_as_new_preserves_some_values() {
|
|
|
2060
2120
|
async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
|
|
2061
2121
|
let mut t = TestHistoryBuilder::default();
|
|
2062
2122
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2063
|
-
let id = t.
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
t.modify_event(id, |e| e.worker_may_ignore = true);
|
|
2072
|
-
if attribs_unset {
|
|
2073
|
-
t.modify_event(id, |e| {
|
|
2074
|
-
e.event_type = EventType::WorkflowPropertiesModifiedExternally as i32;
|
|
2123
|
+
let id = t.add(WorkflowPropertiesModifiedExternallyEventAttributes::default());
|
|
2124
|
+
t.modify_event(id, |e| {
|
|
2125
|
+
e.worker_may_ignore = true;
|
|
2126
|
+
// Ignorable events are ignored if we can't interpret the proto of either the event attribs
|
|
2127
|
+
// or proto - otherwise (this is the _may_ part of may ignore), we'll still try to process
|
|
2128
|
+
// it. That processing may ultimately still choose to do nothing, if we want to _explicitly_
|
|
2129
|
+
// ignore it.
|
|
2130
|
+
if attribs_unset {
|
|
2075
2131
|
e.attributes = None;
|
|
2076
|
-
}
|
|
2077
|
-
|
|
2132
|
+
} else {
|
|
2133
|
+
e.event_type = EventType::Unspecified as i32;
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2078
2136
|
t.add_workflow_task_scheduled_and_started();
|
|
2079
2137
|
|
|
2080
2138
|
let mock = mock_workflow_client();
|
|
@@ -2087,3 +2145,478 @@ async fn ignorable_events_are_ok(#[values(true, false)] attribs_unset: bool) {
|
|
|
2087
2145
|
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2088
2146
|
);
|
|
2089
2147
|
}
|
|
2148
|
+
|
|
2149
|
+
#[tokio::test]
|
|
2150
|
+
async fn fetching_to_continue_replay_works() {
|
|
2151
|
+
let mut mock_client = mock_workflow_client();
|
|
2152
|
+
let mut t = TestHistoryBuilder::default();
|
|
2153
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2154
|
+
t.add_full_wf_task();
|
|
2155
|
+
t.add_full_wf_task(); // ends 7
|
|
2156
|
+
let mut need_fetch_resp =
|
|
2157
|
+
hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
|
|
2158
|
+
need_fetch_resp.next_page_token = vec![1];
|
|
2159
|
+
|
|
2160
|
+
t.add_full_wf_task();
|
|
2161
|
+
t.add_we_signaled("hi", vec![]); // Need to make there be two complete WFTs
|
|
2162
|
+
t.add_full_wf_task(); // end 14
|
|
2163
|
+
let mut fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2164
|
+
t.get_full_history_info().unwrap().into();
|
|
2165
|
+
// Should only contain events after 7
|
|
2166
|
+
if let Some(ref mut h) = fetch_resp.history {
|
|
2167
|
+
h.events.retain(|e| e.event_id >= 8);
|
|
2168
|
+
}
|
|
2169
|
+
// And indicate that even *more* needs to be fetched after this, so we see a request for the
|
|
2170
|
+
// next page happen.
|
|
2171
|
+
fetch_resp.next_page_token = vec![2];
|
|
2172
|
+
|
|
2173
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
2174
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
2175
|
+
t.add_full_wf_task();
|
|
2176
|
+
let mut final_fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2177
|
+
t.get_full_history_info().unwrap().into();
|
|
2178
|
+
// Should have only the final event
|
|
2179
|
+
if let Some(ref mut h) = final_fetch_resp.history {
|
|
2180
|
+
h.events.retain(|e| e.event_id >= 15);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
let tasks = vec![
|
|
2184
|
+
ResponseType::ToTaskNum(1),
|
|
2185
|
+
ResponseType::Raw(need_fetch_resp),
|
|
2186
|
+
];
|
|
2187
|
+
mock_client
|
|
2188
|
+
.expect_get_workflow_execution_history()
|
|
2189
|
+
.returning(move |_, _, _| Ok(fetch_resp.clone()))
|
|
2190
|
+
.times(1);
|
|
2191
|
+
mock_client
|
|
2192
|
+
.expect_get_workflow_execution_history()
|
|
2193
|
+
.returning(move |_, _, _| Ok(final_fetch_resp.clone()))
|
|
2194
|
+
.times(1);
|
|
2195
|
+
let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
|
|
2196
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
2197
|
+
let core = mock_worker(mock);
|
|
2198
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2199
|
+
assert_matches!(
|
|
2200
|
+
act.jobs[0].variant,
|
|
2201
|
+
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2202
|
+
);
|
|
2203
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
2204
|
+
.await
|
|
2205
|
+
.unwrap();
|
|
2206
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2207
|
+
assert_matches!(
|
|
2208
|
+
act.jobs.as_slice(),
|
|
2209
|
+
[WorkflowActivationJob {
|
|
2210
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
2211
|
+
}]
|
|
2212
|
+
);
|
|
2213
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
2214
|
+
act.run_id,
|
|
2215
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
2216
|
+
))
|
|
2217
|
+
.await
|
|
2218
|
+
.unwrap();
|
|
2219
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2220
|
+
assert_matches!(
|
|
2221
|
+
act.jobs.as_slice(),
|
|
2222
|
+
[WorkflowActivationJob {
|
|
2223
|
+
variant: Some(workflow_activation_job::Variant::FireTimer(_)),
|
|
2224
|
+
}]
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
#[tokio::test]
|
|
2229
|
+
async fn fetching_error_evicts_wf() {
|
|
2230
|
+
let mut mock_client = mock_workflow_client();
|
|
2231
|
+
let mut t = TestHistoryBuilder::default();
|
|
2232
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2233
|
+
t.add_workflow_task_scheduled_and_started();
|
|
2234
|
+
t.add_workflow_task_completed();
|
|
2235
|
+
let mut need_fetch_resp =
|
|
2236
|
+
hist_to_poll_resp(&t, "wfid".to_owned(), ResponseType::AllHistory).resp;
|
|
2237
|
+
need_fetch_resp.next_page_token = vec![1];
|
|
2238
|
+
let tasks = vec![
|
|
2239
|
+
ResponseType::ToTaskNum(1),
|
|
2240
|
+
ResponseType::Raw(need_fetch_resp),
|
|
2241
|
+
];
|
|
2242
|
+
mock_client
|
|
2243
|
+
.expect_get_workflow_execution_history()
|
|
2244
|
+
.returning(move |_, _, _| Err(tonic::Status::not_found("Ahh broken")))
|
|
2245
|
+
.times(1);
|
|
2246
|
+
let mut mock = single_hist_mock_sg("wfid", t, tasks, mock_client, true);
|
|
2247
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
2248
|
+
let core = mock_worker(mock);
|
|
2249
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2250
|
+
assert_matches!(
|
|
2251
|
+
act.jobs[0].variant,
|
|
2252
|
+
Some(workflow_activation_job::Variant::StartWorkflow(_))
|
|
2253
|
+
);
|
|
2254
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
2255
|
+
.await
|
|
2256
|
+
.unwrap();
|
|
2257
|
+
let evict_act = core.poll_workflow_activation().await.unwrap();
|
|
2258
|
+
assert_matches!(
|
|
2259
|
+
evict_act.jobs.as_slice(),
|
|
2260
|
+
[WorkflowActivationJob {
|
|
2261
|
+
variant: Some(workflow_activation_job::Variant::RemoveFromCache(r)),
|
|
2262
|
+
}] => r.message.contains("Fetching history failed")
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
/// This test verifies that if we fail to fetch a page during a completion, that we don't get stuck
|
|
2267
|
+
/// in the complete waiting for the completion to finish.
|
|
2268
|
+
#[tokio::test]
|
|
2269
|
+
async fn ensure_fetching_fail_during_complete_sends_task_failure() {
|
|
2270
|
+
let wfid = "fake_wf_id";
|
|
2271
|
+
let mut t = TestHistoryBuilder::default();
|
|
2272
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2273
|
+
t.add_full_wf_task(); // started 3
|
|
2274
|
+
t.add_we_signaled("sig1", vec![]);
|
|
2275
|
+
t.add_full_wf_task(); // started 7
|
|
2276
|
+
t.add_we_signaled("sig2", vec![]);
|
|
2277
|
+
t.add_full_wf_task(); // started 11
|
|
2278
|
+
t.add_workflow_execution_completed();
|
|
2279
|
+
|
|
2280
|
+
let mut first_poll = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(1)).resp;
|
|
2281
|
+
first_poll.next_page_token = vec![1];
|
|
2282
|
+
first_poll.previous_started_event_id = 3;
|
|
2283
|
+
|
|
2284
|
+
let mut next_page: GetWorkflowExecutionHistoryResponse = t.get_history_info(2).unwrap().into();
|
|
2285
|
+
next_page.next_page_token = vec![2];
|
|
2286
|
+
|
|
2287
|
+
let mut mock = mock_workflow_client();
|
|
2288
|
+
mock.expect_get_workflow_execution_history()
|
|
2289
|
+
.returning(move |_, _, _| {
|
|
2290
|
+
error!("Called fetch!");
|
|
2291
|
+
Ok(next_page.clone())
|
|
2292
|
+
})
|
|
2293
|
+
.times(1);
|
|
2294
|
+
let mut really_empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2295
|
+
t.get_history_info(1).unwrap().into();
|
|
2296
|
+
really_empty_fetch_resp.history = Some(Default::default());
|
|
2297
|
+
mock.expect_get_workflow_execution_history()
|
|
2298
|
+
.returning(move |_, _, _| {
|
|
2299
|
+
error!("Called fetch second time!");
|
|
2300
|
+
Ok(really_empty_fetch_resp.clone())
|
|
2301
|
+
})
|
|
2302
|
+
.times(1);
|
|
2303
|
+
mock.expect_fail_workflow_task()
|
|
2304
|
+
.returning(|_, _, _| Ok(Default::default()))
|
|
2305
|
+
.times(1);
|
|
2306
|
+
|
|
2307
|
+
let mut mock = single_hist_mock_sg(wfid, t, [ResponseType::Raw(first_poll)], mock, true);
|
|
2308
|
+
mock.make_wft_stream_interminable();
|
|
2309
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 2);
|
|
2310
|
+
let core = mock_worker(mock);
|
|
2311
|
+
|
|
2312
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2313
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
2314
|
+
.await
|
|
2315
|
+
.unwrap();
|
|
2316
|
+
|
|
2317
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2318
|
+
assert_matches!(
|
|
2319
|
+
wf_task.jobs.as_slice(),
|
|
2320
|
+
[WorkflowActivationJob {
|
|
2321
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
2322
|
+
},]
|
|
2323
|
+
);
|
|
2324
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(wf_task.run_id))
|
|
2325
|
+
.await
|
|
2326
|
+
.unwrap();
|
|
2327
|
+
|
|
2328
|
+
// Expect to see eviction b/c of history fetching error here.
|
|
2329
|
+
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
2330
|
+
assert_matches!(
|
|
2331
|
+
wf_task.jobs.as_slice(),
|
|
2332
|
+
[WorkflowActivationJob {
|
|
2333
|
+
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
2334
|
+
},]
|
|
2335
|
+
);
|
|
2336
|
+
|
|
2337
|
+
core.shutdown().await;
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
#[tokio::test]
|
|
2341
|
+
async fn lang_internal_flags() {
|
|
2342
|
+
let mut t = TestHistoryBuilder::default();
|
|
2343
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2344
|
+
t.add_full_wf_task();
|
|
2345
|
+
t.set_flags_first_wft(&[], &[1]);
|
|
2346
|
+
t.add_we_signaled("sig1", vec![]);
|
|
2347
|
+
t.add_full_wf_task();
|
|
2348
|
+
t.set_flags_last_wft(&[], &[2]);
|
|
2349
|
+
t.add_we_signaled("sig2", vec![]);
|
|
2350
|
+
t.add_full_wf_task();
|
|
2351
|
+
t.add_workflow_execution_completed();
|
|
2352
|
+
|
|
2353
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
2354
|
+
"fake_wf_id",
|
|
2355
|
+
t,
|
|
2356
|
+
[ResponseType::ToTaskNum(2), ResponseType::AllHistory],
|
|
2357
|
+
mock_workflow_client(),
|
|
2358
|
+
);
|
|
2359
|
+
mh.completion_asserts = Some(Box::new(|c| {
|
|
2360
|
+
assert_matches!(c.sdk_metadata.lang_used_flags.as_slice(), &[2]);
|
|
2361
|
+
}));
|
|
2362
|
+
let mut mock = build_mock_pollers(mh);
|
|
2363
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
2364
|
+
let core = mock_worker(mock);
|
|
2365
|
+
|
|
2366
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2367
|
+
assert_matches!(act.available_internal_flags.as_slice(), [1]);
|
|
2368
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
2369
|
+
.await
|
|
2370
|
+
.unwrap();
|
|
2371
|
+
|
|
2372
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2373
|
+
let mut completion = WorkflowActivationCompletion::empty(act.run_id);
|
|
2374
|
+
completion.add_internal_flags(2);
|
|
2375
|
+
core.complete_workflow_activation(completion).await.unwrap();
|
|
2376
|
+
|
|
2377
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2378
|
+
assert_matches!(act.available_internal_flags.as_slice(), [1, 2]);
|
|
2379
|
+
core.complete_execution(&act.run_id).await;
|
|
2380
|
+
core.shutdown().await;
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
// Verify we send flags to server when they're used
|
|
2384
|
+
#[tokio::test]
|
|
2385
|
+
async fn core_internal_flags() {
|
|
2386
|
+
let mut t = TestHistoryBuilder::default();
|
|
2387
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2388
|
+
t.add_full_wf_task();
|
|
2389
|
+
let act_scheduled_event_id = t.add_activity_task_scheduled("act-id");
|
|
2390
|
+
let act_started_event_id = t.add_activity_task_started(act_scheduled_event_id);
|
|
2391
|
+
t.add_activity_task_completed(
|
|
2392
|
+
act_scheduled_event_id,
|
|
2393
|
+
act_started_event_id,
|
|
2394
|
+
Default::default(),
|
|
2395
|
+
);
|
|
2396
|
+
t.add_full_wf_task();
|
|
2397
|
+
t.add_workflow_execution_completed();
|
|
2398
|
+
|
|
2399
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
2400
|
+
"fake_wf_id",
|
|
2401
|
+
t,
|
|
2402
|
+
[ResponseType::ToTaskNum(1), ResponseType::ToTaskNum(2)],
|
|
2403
|
+
mock_workflow_client(),
|
|
2404
|
+
);
|
|
2405
|
+
let first_poll = AtomicBool::new(true);
|
|
2406
|
+
mh.completion_asserts = Some(Box::new(move |c| {
|
|
2407
|
+
if !first_poll.load(Ordering::Acquire) {
|
|
2408
|
+
assert_matches!(c.sdk_metadata.core_used_flags.as_slice(), &[1]);
|
|
2409
|
+
}
|
|
2410
|
+
first_poll.store(false, Ordering::Release);
|
|
2411
|
+
}));
|
|
2412
|
+
let mut mock = build_mock_pollers(mh);
|
|
2413
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
2414
|
+
let core = mock_worker(mock);
|
|
2415
|
+
|
|
2416
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2417
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
2418
|
+
act.run_id,
|
|
2419
|
+
schedule_activity_cmd(
|
|
2420
|
+
1,
|
|
2421
|
+
"whatever",
|
|
2422
|
+
"act-id",
|
|
2423
|
+
ActivityCancellationType::TryCancel,
|
|
2424
|
+
Duration::from_secs(60),
|
|
2425
|
+
Duration::from_secs(60),
|
|
2426
|
+
),
|
|
2427
|
+
))
|
|
2428
|
+
.await
|
|
2429
|
+
.unwrap();
|
|
2430
|
+
|
|
2431
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2432
|
+
core.complete_execution(&act.run_id).await;
|
|
2433
|
+
core.shutdown().await;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
#[tokio::test]
|
|
2437
|
+
async fn post_terminal_commands_are_discarded() {
|
|
2438
|
+
let mut t = TestHistoryBuilder::default();
|
|
2439
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2440
|
+
t.add_full_wf_task();
|
|
2441
|
+
t.add_workflow_execution_completed();
|
|
2442
|
+
|
|
2443
|
+
let mut mh = MockPollCfg::from_resp_batches(
|
|
2444
|
+
"fake_wf_id",
|
|
2445
|
+
t,
|
|
2446
|
+
[ResponseType::ToTaskNum(1), ResponseType::AllHistory],
|
|
2447
|
+
mock_workflow_client(),
|
|
2448
|
+
);
|
|
2449
|
+
mh.completion_asserts = Some(Box::new(|c| {
|
|
2450
|
+
// Only the complete execution command should actually be sent
|
|
2451
|
+
assert_eq!(c.commands.len(), 1);
|
|
2452
|
+
}));
|
|
2453
|
+
let mut mock = build_mock_pollers(mh);
|
|
2454
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
2455
|
+
let core = mock_worker(mock);
|
|
2456
|
+
|
|
2457
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2458
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
2459
|
+
act.run_id,
|
|
2460
|
+
vec![
|
|
2461
|
+
CompleteWorkflowExecution { result: None }.into(),
|
|
2462
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
2463
|
+
],
|
|
2464
|
+
))
|
|
2465
|
+
.await
|
|
2466
|
+
.unwrap();
|
|
2467
|
+
|
|
2468
|
+
// This just ensures applying the complete history w/ the completion command works, though
|
|
2469
|
+
// there's no activation.
|
|
2470
|
+
let act = core.poll_workflow_activation().await;
|
|
2471
|
+
assert_matches!(act.unwrap_err(), PollWfError::ShutDown);
|
|
2472
|
+
|
|
2473
|
+
core.shutdown().await;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
// Lang expects to always see jobs in this order:
|
|
2477
|
+
// patches, signals, everything else, queries
|
|
2478
|
+
#[tokio::test]
|
|
2479
|
+
async fn jobs_are_in_appropriate_order() {
|
|
2480
|
+
let p1 = "patchy-mc-patchface";
|
|
2481
|
+
let p2 = "enchi-the-kitty";
|
|
2482
|
+
let mut t = TestHistoryBuilder::default();
|
|
2483
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2484
|
+
t.add_full_wf_task();
|
|
2485
|
+
t.add_has_change_marker(p1, false);
|
|
2486
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
2487
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
2488
|
+
t.add_we_signaled("yummy-salmon", vec![]);
|
|
2489
|
+
t.add_full_wf_task();
|
|
2490
|
+
t.add_has_change_marker(p2, false);
|
|
2491
|
+
t.add_workflow_execution_completed();
|
|
2492
|
+
|
|
2493
|
+
let mh = MockPollCfg::from_resp_batches(
|
|
2494
|
+
"fake_wf_id",
|
|
2495
|
+
t,
|
|
2496
|
+
[ResponseType::AllHistory],
|
|
2497
|
+
mock_workflow_client(),
|
|
2498
|
+
);
|
|
2499
|
+
let mut mock = build_mock_pollers(mh);
|
|
2500
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
2501
|
+
let core = mock_worker(mock);
|
|
2502
|
+
|
|
2503
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2504
|
+
// Patch notifications always come first
|
|
2505
|
+
assert_matches!(
|
|
2506
|
+
act.jobs[0].variant.as_ref().unwrap(),
|
|
2507
|
+
workflow_activation_job::Variant::NotifyHasPatch(_)
|
|
2508
|
+
);
|
|
2509
|
+
assert_matches!(
|
|
2510
|
+
act.jobs[1].variant.as_ref().unwrap(),
|
|
2511
|
+
workflow_activation_job::Variant::StartWorkflow(_)
|
|
2512
|
+
);
|
|
2513
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
2514
|
+
act.run_id,
|
|
2515
|
+
vec![
|
|
2516
|
+
SetPatchMarker {
|
|
2517
|
+
patch_id: p1.to_string(),
|
|
2518
|
+
deprecated: false,
|
|
2519
|
+
}
|
|
2520
|
+
.into(),
|
|
2521
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
2522
|
+
],
|
|
2523
|
+
))
|
|
2524
|
+
.await
|
|
2525
|
+
.unwrap();
|
|
2526
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
2527
|
+
assert_matches!(
|
|
2528
|
+
act.jobs[0].variant.as_ref().unwrap(),
|
|
2529
|
+
workflow_activation_job::Variant::NotifyHasPatch(_)
|
|
2530
|
+
);
|
|
2531
|
+
assert_matches!(
|
|
2532
|
+
act.jobs[1].variant.as_ref().unwrap(),
|
|
2533
|
+
workflow_activation_job::Variant::SignalWorkflow(_)
|
|
2534
|
+
);
|
|
2535
|
+
assert_matches!(
|
|
2536
|
+
act.jobs[2].variant.as_ref().unwrap(),
|
|
2537
|
+
workflow_activation_job::Variant::FireTimer(_)
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
#[rstest]
|
|
2542
|
+
#[tokio::test]
|
|
2543
|
+
async fn history_length_with_fail_and_timeout(
|
|
2544
|
+
#[values(true, false)] use_cache: bool,
|
|
2545
|
+
#[values(1, 2, 3)] history_responses_case: u8,
|
|
2546
|
+
) {
|
|
2547
|
+
let wfid = "fake_wf_id";
|
|
2548
|
+
let mut t = TestHistoryBuilder::default();
|
|
2549
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2550
|
+
t.add_full_wf_task();
|
|
2551
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
2552
|
+
t.add_timer_fired(timer_started_event_id, "1".to_string());
|
|
2553
|
+
t.add_workflow_task_scheduled_and_started();
|
|
2554
|
+
t.add_workflow_task_failed_with_failure(WorkflowTaskFailedCause::Unspecified, "ahh".into());
|
|
2555
|
+
t.add_workflow_task_scheduled_and_started();
|
|
2556
|
+
t.add_workflow_task_timed_out();
|
|
2557
|
+
t.add_full_wf_task();
|
|
2558
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
2559
|
+
t.add_timer_fired(timer_started_event_id, "2".to_string());
|
|
2560
|
+
t.add_full_wf_task();
|
|
2561
|
+
t.add_workflow_execution_completed();
|
|
2562
|
+
|
|
2563
|
+
let mut mock_client = mock_workflow_client();
|
|
2564
|
+
let history_responses = match history_responses_case {
|
|
2565
|
+
1 => vec![ResponseType::AllHistory],
|
|
2566
|
+
2 => vec![
|
|
2567
|
+
ResponseType::ToTaskNum(1),
|
|
2568
|
+
ResponseType::ToTaskNum(2),
|
|
2569
|
+
ResponseType::AllHistory,
|
|
2570
|
+
],
|
|
2571
|
+
3 => {
|
|
2572
|
+
let mut needs_fetch = hist_to_poll_resp(&t, wfid, ResponseType::ToTaskNum(2)).resp;
|
|
2573
|
+
needs_fetch.next_page_token = vec![1];
|
|
2574
|
+
// Truncate the history a bit in order to force incomplete WFT
|
|
2575
|
+
needs_fetch.history.as_mut().unwrap().events.truncate(6);
|
|
2576
|
+
let needs_fetch_resp = ResponseType::Raw(needs_fetch);
|
|
2577
|
+
let mut empty_fetch_resp: GetWorkflowExecutionHistoryResponse =
|
|
2578
|
+
t.get_history_info(1).unwrap().into();
|
|
2579
|
+
empty_fetch_resp.history.as_mut().unwrap().events = vec![];
|
|
2580
|
+
mock_client
|
|
2581
|
+
.expect_get_workflow_execution_history()
|
|
2582
|
+
.returning(move |_, _, _| Ok(empty_fetch_resp.clone()))
|
|
2583
|
+
.times(1);
|
|
2584
|
+
vec![
|
|
2585
|
+
ResponseType::ToTaskNum(1),
|
|
2586
|
+
needs_fetch_resp,
|
|
2587
|
+
ResponseType::ToTaskNum(2),
|
|
2588
|
+
ResponseType::AllHistory,
|
|
2589
|
+
]
|
|
2590
|
+
}
|
|
2591
|
+
_ => unreachable!(),
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
let mut mh = MockPollCfg::from_resp_batches(wfid, t, history_responses, mock_client);
|
|
2595
|
+
if history_responses_case == 3 {
|
|
2596
|
+
// Expect the failed pagination fetch
|
|
2597
|
+
mh.num_expected_fails = 1;
|
|
2598
|
+
}
|
|
2599
|
+
let mut worker = mock_sdk_cfg(mh, |wc| {
|
|
2600
|
+
if use_cache {
|
|
2601
|
+
wc.max_cached_workflows = 1;
|
|
2602
|
+
}
|
|
2603
|
+
});
|
|
2604
|
+
worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
|
|
2605
|
+
assert_eq!(ctx.history_length(), 3);
|
|
2606
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
2607
|
+
assert_eq!(ctx.history_length(), 14);
|
|
2608
|
+
ctx.timer(Duration::from_secs(1)).await;
|
|
2609
|
+
assert_eq!(ctx.history_length(), 19);
|
|
2610
|
+
Ok(().into())
|
|
2611
|
+
});
|
|
2612
|
+
worker
|
|
2613
|
+
.submit_wf(
|
|
2614
|
+
wfid.to_owned(),
|
|
2615
|
+
DEFAULT_WORKFLOW_TYPE.to_owned(),
|
|
2616
|
+
vec![],
|
|
2617
|
+
WorkflowOptions::default(),
|
|
2618
|
+
)
|
|
2619
|
+
.await
|
|
2620
|
+
.unwrap();
|
|
2621
|
+
worker.run_until_done().await.unwrap();
|
|
2622
|
+
}
|