@temporalio/core-bridge 1.1.0 → 1.3.1
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 +786 -54
- package/Cargo.toml +2 -2
- package/common.js +7 -3
- package/index.d.ts +110 -3
- package/index.js +2 -6
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/scripts/build.js +4 -3
- package/sdk-core/.buildkite/docker/Dockerfile +2 -1
- package/sdk-core/ARCHITECTURE.md +2 -2
- package/sdk-core/README.md +12 -0
- package/sdk-core/bridge-ffi/Cargo.toml +2 -2
- package/sdk-core/client/Cargo.toml +6 -4
- package/sdk-core/client/src/lib.rs +338 -215
- package/sdk-core/client/src/raw.rs +352 -106
- package/sdk-core/client/src/retry.rs +159 -133
- package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
- package/sdk-core/core/Cargo.toml +18 -9
- package/sdk-core/core/src/core_tests/activity_tasks.rs +63 -23
- package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
- package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
- package/sdk-core/core/src/core_tests/workers.rs +3 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
- package/sdk-core/core/src/ephemeral_server/mod.rs +499 -0
- package/sdk-core/core/src/lib.rs +60 -26
- package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
- package/sdk-core/core/src/replay/mod.rs +3 -3
- package/sdk-core/core/src/retry_logic.rs +10 -9
- package/sdk-core/core/src/telemetry/mod.rs +10 -7
- package/sdk-core/core/src/test_help/mod.rs +18 -8
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
- package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
- package/sdk-core/core/src/worker/activities.rs +6 -12
- package/sdk-core/core/src/worker/client.rs +193 -64
- package/sdk-core/core/src/worker/mod.rs +14 -19
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
- package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
- package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
- package/sdk-core/core/src/worker/workflow/mod.rs +59 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
- package/sdk-core/core-api/Cargo.toml +2 -2
- package/sdk-core/core-api/src/errors.rs +3 -11
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
- package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
- package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
- package/sdk-core/protos/api_upstream/Makefile +2 -2
- package/sdk-core/protos/api_upstream/buf.yaml +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
- package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
- package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
- package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
- package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +2 -2
- package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
- package/sdk-core/sdk/src/workflow_context.rs +30 -6
- package/sdk-core/sdk/src/workflow_future.rs +4 -4
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
- package/sdk-core/sdk-core-protos/build.rs +9 -1
- package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
- package/sdk-core/test-utils/Cargo.toml +3 -3
- package/sdk-core/test-utils/src/canned_histories.rs +58 -0
- package/sdk-core/test-utils/src/lib.rs +14 -10
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +141 -0
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
- package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
- package/sdk-core/tests/load_tests.rs +2 -1
- package/sdk-core/tests/main.rs +10 -0
- package/src/conversions.rs +138 -91
- package/src/helpers.rs +190 -0
- package/src/lib.rs +10 -912
- package/src/runtime.rs +436 -0
- package/src/testing.rs +67 -0
- package/src/worker.rs +465 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
advance_fut, job_assert,
|
|
2
|
+
advance_fut, job_assert, prost_dur,
|
|
3
3
|
test_help::{
|
|
4
4
|
build_fake_worker, build_mock_pollers, canned_histories, gen_assert_and_reply,
|
|
5
5
|
mock_manual_poller, mock_poller, mock_poller_from_resps, mock_worker, poll_and_reply,
|
|
@@ -23,6 +23,7 @@ use std::{
|
|
|
23
23
|
use temporal_client::WorkflowOptions;
|
|
24
24
|
use temporal_sdk::{ActivityOptions, WfContext};
|
|
25
25
|
use temporal_sdk_core_api::{errors::CompleteActivityError, Worker as WorkerTrait};
|
|
26
|
+
use temporal_sdk_core_protos::temporal::api::command::v1::ScheduleActivityTaskCommandAttributes;
|
|
26
27
|
use temporal_sdk_core_protos::{
|
|
27
28
|
coresdk::{
|
|
28
29
|
activity_result::{
|
|
@@ -149,14 +150,14 @@ async fn heartbeats_report_cancels_only_once() {
|
|
|
149
150
|
PollActivityTaskQueueResponse {
|
|
150
151
|
task_token: vec![1],
|
|
151
152
|
activity_id: "act1".to_string(),
|
|
152
|
-
heartbeat_timeout: Some(
|
|
153
|
+
heartbeat_timeout: Some(prost_dur!(from_millis(1))),
|
|
153
154
|
..Default::default()
|
|
154
155
|
}
|
|
155
156
|
.into(),
|
|
156
157
|
PollActivityTaskQueueResponse {
|
|
157
158
|
task_token: vec![2],
|
|
158
159
|
activity_id: "act2".to_string(),
|
|
159
|
-
heartbeat_timeout: Some(
|
|
160
|
+
heartbeat_timeout: Some(prost_dur!(from_millis(1))),
|
|
160
161
|
..Default::default()
|
|
161
162
|
}
|
|
162
163
|
.into(),
|
|
@@ -226,7 +227,7 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
226
227
|
async {
|
|
227
228
|
Some(Ok(PollActivityTaskQueueResponse {
|
|
228
229
|
task_token: vec![1],
|
|
229
|
-
heartbeat_timeout: Some(
|
|
230
|
+
heartbeat_timeout: Some(prost_dur!(from_secs(1))),
|
|
230
231
|
..Default::default()
|
|
231
232
|
}))
|
|
232
233
|
}
|
|
@@ -263,7 +264,7 @@ async fn activity_cancel_interrupts_poll() {
|
|
|
263
264
|
act_poller: Some(Box::from(mock_poller)),
|
|
264
265
|
..Default::default()
|
|
265
266
|
};
|
|
266
|
-
let core = mock_worker(MocksHolder::from_mock_worker(mock_client
|
|
267
|
+
let core = mock_worker(MocksHolder::from_mock_worker(mock_client, mw));
|
|
267
268
|
let last_finisher = AtomicUsize::new(0);
|
|
268
269
|
// Perform first poll to get the activity registered
|
|
269
270
|
let act = core.poll_activity_task().await.unwrap();
|
|
@@ -315,7 +316,7 @@ async fn activity_poll_timeout_retries() {
|
|
|
315
316
|
act_poller: Some(Box::from(mock_act_poller)),
|
|
316
317
|
..Default::default()
|
|
317
318
|
};
|
|
318
|
-
let core = mock_worker(MocksHolder::from_mock_worker(mock_client
|
|
319
|
+
let core = mock_worker(MocksHolder::from_mock_worker(mock_client, mw));
|
|
319
320
|
let r = core.poll_activity_task().await.unwrap();
|
|
320
321
|
assert_matches!(r.task_token.as_slice(), b"hello!");
|
|
321
322
|
}
|
|
@@ -333,7 +334,7 @@ async fn many_concurrent_heartbeat_cancels() {
|
|
|
333
334
|
async move {
|
|
334
335
|
Ok(PollActivityTaskQueueResponse {
|
|
335
336
|
task_token: i.to_be_bytes().to_vec(),
|
|
336
|
-
heartbeat_timeout: Some(
|
|
337
|
+
heartbeat_timeout: Some(prost_dur!(from_millis(200))),
|
|
337
338
|
..Default::default()
|
|
338
339
|
})
|
|
339
340
|
}
|
|
@@ -506,7 +507,7 @@ async fn can_heartbeat_acts_during_shutdown() {
|
|
|
506
507
|
[PollActivityTaskQueueResponse {
|
|
507
508
|
task_token: vec![1],
|
|
508
509
|
activity_id: "act1".to_string(),
|
|
509
|
-
heartbeat_timeout: Some(
|
|
510
|
+
heartbeat_timeout: Some(prost_dur!(from_millis(1))),
|
|
510
511
|
..Default::default()
|
|
511
512
|
}
|
|
512
513
|
.into()],
|
|
@@ -559,7 +560,7 @@ async fn complete_act_with_fail_flushes_heartbeat() {
|
|
|
559
560
|
[PollActivityTaskQueueResponse {
|
|
560
561
|
task_token: vec![1],
|
|
561
562
|
activity_id: "act1".to_string(),
|
|
562
|
-
heartbeat_timeout: Some(
|
|
563
|
+
heartbeat_timeout: Some(prost_dur!(from_secs(10))),
|
|
563
564
|
..Default::default()
|
|
564
565
|
}
|
|
565
566
|
.into()],
|
|
@@ -620,21 +621,46 @@ async fn activity_tasks_from_completion_are_delivered() {
|
|
|
620
621
|
let mut t = TestHistoryBuilder::default();
|
|
621
622
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
622
623
|
t.add_full_wf_task();
|
|
623
|
-
let
|
|
624
|
-
let
|
|
625
|
-
|
|
624
|
+
let act_same_queue_sched_id = t.add_activity_task_scheduled("act_id_same_queue");
|
|
625
|
+
let act_different_queue_sched_id = t.add_activity_task_scheduled("act_id_different_queue");
|
|
626
|
+
let act_same_queue_start_id = t.add_activity_task_started(act_same_queue_sched_id);
|
|
627
|
+
t.add_activity_task_completed(
|
|
628
|
+
act_same_queue_sched_id,
|
|
629
|
+
act_same_queue_start_id,
|
|
630
|
+
b"hi".into(),
|
|
631
|
+
);
|
|
626
632
|
t.add_full_wf_task();
|
|
633
|
+
t.add_activity_task_cancel_requested(act_different_queue_sched_id);
|
|
627
634
|
t.add_workflow_execution_completed();
|
|
628
635
|
|
|
636
|
+
let num_eager_requested = Arc::new(AtomicUsize::new(0));
|
|
637
|
+
// Clone it to move into the callback below
|
|
638
|
+
let num_eager_requested_clone = num_eager_requested.clone();
|
|
639
|
+
|
|
629
640
|
let mut mock = mock_workflow_client();
|
|
630
641
|
mock.expect_complete_workflow_task()
|
|
631
642
|
.times(1)
|
|
632
|
-
.returning(move |
|
|
643
|
+
.returning(move |req| {
|
|
644
|
+
// Store the number of eager activities requested to be checked below
|
|
645
|
+
let count = req
|
|
646
|
+
.commands
|
|
647
|
+
.into_iter()
|
|
648
|
+
.filter(|c| match c.attributes {
|
|
649
|
+
Some(Attributes::ScheduleActivityTaskCommandAttributes(
|
|
650
|
+
ScheduleActivityTaskCommandAttributes {
|
|
651
|
+
request_eager_execution,
|
|
652
|
+
..
|
|
653
|
+
},
|
|
654
|
+
)) => request_eager_execution,
|
|
655
|
+
_ => false,
|
|
656
|
+
})
|
|
657
|
+
.count();
|
|
658
|
+
num_eager_requested_clone.store(count, Ordering::Relaxed);
|
|
633
659
|
Ok(RespondWorkflowTaskCompletedResponse {
|
|
634
660
|
workflow_task: None,
|
|
635
661
|
activity_tasks: vec![PollActivityTaskQueueResponse {
|
|
636
662
|
task_token: vec![1],
|
|
637
|
-
activity_id: "
|
|
663
|
+
activity_id: "act_id_same_queue".to_string(),
|
|
638
664
|
..Default::default()
|
|
639
665
|
}],
|
|
640
666
|
})
|
|
@@ -652,15 +678,26 @@ async fn activity_tasks_from_completion_are_delivered() {
|
|
|
652
678
|
let core = mock_worker(mock);
|
|
653
679
|
|
|
654
680
|
let wf_task = core.poll_workflow_activation().await.unwrap();
|
|
655
|
-
core.complete_workflow_activation(WorkflowActivationCompletion::
|
|
681
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
656
682
|
wf_task.run_id,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
683
|
+
vec![
|
|
684
|
+
ScheduleActivity {
|
|
685
|
+
seq: 1,
|
|
686
|
+
activity_id: "act_id_same_queue".to_string(),
|
|
687
|
+
task_queue: TEST_Q.to_string(),
|
|
688
|
+
cancellation_type: ActivityCancellationType::TryCancel as i32,
|
|
689
|
+
..Default::default()
|
|
690
|
+
}
|
|
691
|
+
.into(),
|
|
692
|
+
ScheduleActivity {
|
|
693
|
+
seq: 2,
|
|
694
|
+
activity_id: "act_id_different_queue".to_string(),
|
|
695
|
+
task_queue: "different_queue".to_string(),
|
|
696
|
+
cancellation_type: ActivityCancellationType::Abandon as i32,
|
|
697
|
+
..Default::default()
|
|
698
|
+
}
|
|
699
|
+
.into(),
|
|
700
|
+
],
|
|
664
701
|
))
|
|
665
702
|
.await
|
|
666
703
|
.unwrap();
|
|
@@ -677,6 +714,9 @@ async fn activity_tasks_from_completion_are_delivered() {
|
|
|
677
714
|
.unwrap();
|
|
678
715
|
|
|
679
716
|
core.shutdown().await;
|
|
717
|
+
|
|
718
|
+
// Verify only a single eager activity was scheduled (the one on our worker's task queue)
|
|
719
|
+
assert_eq!(num_eager_requested.load(Ordering::Relaxed), 1);
|
|
680
720
|
}
|
|
681
721
|
|
|
682
722
|
#[tokio::test]
|
|
@@ -818,7 +858,7 @@ async fn retryable_net_error_exhaustion_is_nonfatal() {
|
|
|
818
858
|
[PollActivityTaskQueueResponse {
|
|
819
859
|
task_token: vec![1],
|
|
820
860
|
activity_id: "act1".to_string(),
|
|
821
|
-
heartbeat_timeout: Some(
|
|
861
|
+
heartbeat_timeout: Some(prost_dur!(from_secs(10))),
|
|
822
862
|
..Default::default()
|
|
823
863
|
}
|
|
824
864
|
.into()],
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
replay::DEFAULT_WORKFLOW_TYPE,
|
|
3
|
-
test_help::{
|
|
3
|
+
test_help::{
|
|
4
|
+
canned_histories, mock_sdk, mock_worker, single_hist_mock_sg, MockPollCfg, ResponseType,
|
|
5
|
+
},
|
|
4
6
|
worker::{client::mocks::mock_workflow_client, ManagedWFFunc},
|
|
5
7
|
};
|
|
6
8
|
use temporal_client::WorkflowOptions;
|
|
7
9
|
use temporal_sdk::{ChildWorkflowOptions, Signal, WfContext, WorkflowFunction, WorkflowResult};
|
|
8
|
-
use
|
|
9
|
-
|
|
10
|
+
use temporal_sdk_core_api::Worker;
|
|
11
|
+
use temporal_sdk_core_protos::coresdk::{
|
|
12
|
+
child_workflow::{child_workflow_result, ChildWorkflowCancellationType},
|
|
13
|
+
workflow_activation::{workflow_activation_job, WorkflowActivationJob},
|
|
14
|
+
workflow_commands::{
|
|
15
|
+
CancelChildWorkflowExecution, CompleteWorkflowExecution, StartChildWorkflowExecution,
|
|
16
|
+
},
|
|
17
|
+
workflow_completion::WorkflowActivationCompletion,
|
|
10
18
|
};
|
|
11
19
|
use tokio::join;
|
|
12
20
|
|
|
@@ -97,3 +105,117 @@ async fn cancel_child_workflow() {
|
|
|
97
105
|
wfm.process_all_activations().await.unwrap();
|
|
98
106
|
wfm.shutdown().await.unwrap();
|
|
99
107
|
}
|
|
108
|
+
|
|
109
|
+
#[rstest::rstest]
|
|
110
|
+
#[case::abandon(ChildWorkflowCancellationType::Abandon)]
|
|
111
|
+
#[case::try_cancel(ChildWorkflowCancellationType::TryCancel)]
|
|
112
|
+
#[case::wait_cancel_completed(ChildWorkflowCancellationType::WaitCancellationCompleted)]
|
|
113
|
+
#[tokio::test]
|
|
114
|
+
async fn cancel_child_workflow_lang_thinks_not_started_but_is(
|
|
115
|
+
#[case] cancellation_type: ChildWorkflowCancellationType,
|
|
116
|
+
) {
|
|
117
|
+
// Since signal handlers always run first, it's possible lang might try to cancel
|
|
118
|
+
// a child workflow it thinks isn't started, but we've told it is in the same activation.
|
|
119
|
+
// It would be annoying for lang to have to peek ahead at jobs to be consistent in that case.
|
|
120
|
+
let t = match cancellation_type {
|
|
121
|
+
ChildWorkflowCancellationType::Abandon => {
|
|
122
|
+
canned_histories::single_child_workflow_abandon_cancelled("child-id-1")
|
|
123
|
+
}
|
|
124
|
+
ChildWorkflowCancellationType::TryCancel => {
|
|
125
|
+
canned_histories::single_child_workflow_try_cancelled("child-id-1")
|
|
126
|
+
}
|
|
127
|
+
_ => canned_histories::single_child_workflow_cancelled("child-id-1"),
|
|
128
|
+
};
|
|
129
|
+
let mock = mock_workflow_client();
|
|
130
|
+
let mock = single_hist_mock_sg("fakeid", t, [ResponseType::AllHistory], mock, true);
|
|
131
|
+
let core = mock_worker(mock);
|
|
132
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
133
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
134
|
+
act.run_id,
|
|
135
|
+
StartChildWorkflowExecution {
|
|
136
|
+
seq: 1,
|
|
137
|
+
cancellation_type: cancellation_type as i32,
|
|
138
|
+
..Default::default()
|
|
139
|
+
}
|
|
140
|
+
.into(),
|
|
141
|
+
))
|
|
142
|
+
.await
|
|
143
|
+
.unwrap();
|
|
144
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
145
|
+
assert_matches!(
|
|
146
|
+
act.jobs.as_slice(),
|
|
147
|
+
[WorkflowActivationJob {
|
|
148
|
+
variant: Some(workflow_activation_job::Variant::ResolveChildWorkflowExecutionStart(_)),
|
|
149
|
+
}]
|
|
150
|
+
);
|
|
151
|
+
// Issue the cancel command
|
|
152
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
153
|
+
act.run_id,
|
|
154
|
+
CancelChildWorkflowExecution {
|
|
155
|
+
child_workflow_seq: 1,
|
|
156
|
+
}
|
|
157
|
+
.into(),
|
|
158
|
+
))
|
|
159
|
+
.await
|
|
160
|
+
.unwrap();
|
|
161
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
162
|
+
// Make sure that a resolve for the "request cancel external workflow" command does *not* appear
|
|
163
|
+
// since lang didn't actually issue one. The only job should be resolving the child workflow.
|
|
164
|
+
assert_matches!(
|
|
165
|
+
act.jobs.as_slice(),
|
|
166
|
+
[WorkflowActivationJob {
|
|
167
|
+
variant: Some(workflow_activation_job::Variant::ResolveChildWorkflowExecution(_)),
|
|
168
|
+
}]
|
|
169
|
+
);
|
|
170
|
+
// Request cancel external is technically fallible, but the only reasons relate to targeting
|
|
171
|
+
// a not-found workflow, which couldn't happen in this case.
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
#[tokio::test]
|
|
175
|
+
async fn cancel_already_complete_child_ignored() {
|
|
176
|
+
let t = canned_histories::single_child_workflow("child-id-1");
|
|
177
|
+
let mock = mock_workflow_client();
|
|
178
|
+
let mock = single_hist_mock_sg("fakeid", t, [ResponseType::AllHistory], mock, true);
|
|
179
|
+
let core = mock_worker(mock);
|
|
180
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
181
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
182
|
+
act.run_id,
|
|
183
|
+
StartChildWorkflowExecution {
|
|
184
|
+
seq: 1,
|
|
185
|
+
..Default::default()
|
|
186
|
+
}
|
|
187
|
+
.into(),
|
|
188
|
+
))
|
|
189
|
+
.await
|
|
190
|
+
.unwrap();
|
|
191
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
192
|
+
assert_matches!(
|
|
193
|
+
act.jobs.as_slice(),
|
|
194
|
+
[WorkflowActivationJob {
|
|
195
|
+
variant: Some(workflow_activation_job::Variant::ResolveChildWorkflowExecutionStart(_)),
|
|
196
|
+
}]
|
|
197
|
+
);
|
|
198
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(act.run_id))
|
|
199
|
+
.await
|
|
200
|
+
.unwrap();
|
|
201
|
+
let act = core.poll_workflow_activation().await.unwrap();
|
|
202
|
+
assert_matches!(
|
|
203
|
+
act.jobs.as_slice(),
|
|
204
|
+
[WorkflowActivationJob {
|
|
205
|
+
variant: Some(workflow_activation_job::Variant::ResolveChildWorkflowExecution(_)),
|
|
206
|
+
}]
|
|
207
|
+
);
|
|
208
|
+
// Try to cancel post-completion, it should be ignored. Also complete the wf.
|
|
209
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
210
|
+
act.run_id,
|
|
211
|
+
vec![
|
|
212
|
+
CancelChildWorkflowExecution {
|
|
213
|
+
child_workflow_seq: 1,
|
|
214
|
+
}
|
|
215
|
+
.into(),
|
|
216
|
+
CompleteWorkflowExecution { result: None }.into(),
|
|
217
|
+
],
|
|
218
|
+
))
|
|
219
|
+
.await
|
|
220
|
+
.unwrap();
|
|
221
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
+
prost_dur,
|
|
2
3
|
replay::{default_wes_attribs, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE},
|
|
3
4
|
test_help::{
|
|
4
5
|
hist_to_poll_resp, mock_sdk, mock_sdk_cfg, mock_worker, single_hist_mock_sg, MockPollCfg,
|
|
@@ -162,7 +163,7 @@ async fn local_act_heartbeat(#[case] shutdown_middle: bool) {
|
|
|
162
163
|
let mut t = TestHistoryBuilder::default();
|
|
163
164
|
let wft_timeout = Duration::from_millis(200);
|
|
164
165
|
let mut wes_short_wft_timeout = default_wes_attribs();
|
|
165
|
-
wes_short_wft_timeout.workflow_task_timeout = Some(wft_timeout.
|
|
166
|
+
wes_short_wft_timeout.workflow_task_timeout = Some(wft_timeout.try_into().unwrap());
|
|
166
167
|
t.add(
|
|
167
168
|
EventType::WorkflowExecutionStarted,
|
|
168
169
|
wes_short_wft_timeout.into(),
|
|
@@ -247,7 +248,7 @@ async fn local_act_fail_and_retry(#[case] eventually_pass: bool) {
|
|
|
247
248
|
activity_type: "echo".to_string(),
|
|
248
249
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
249
250
|
retry_policy: RetryPolicy {
|
|
250
|
-
initial_interval: Some(
|
|
251
|
+
initial_interval: Some(prost_dur!(from_millis(50))),
|
|
251
252
|
backoff_coefficient: 1.2,
|
|
252
253
|
maximum_interval: None,
|
|
253
254
|
maximum_attempts: 5,
|
|
@@ -328,10 +329,10 @@ async fn local_act_retry_long_backoff_uses_timer() {
|
|
|
328
329
|
activity_type: "echo".to_string(),
|
|
329
330
|
input: "hi".as_json_payload().expect("serializes fine"),
|
|
330
331
|
retry_policy: RetryPolicy {
|
|
331
|
-
initial_interval: Some(
|
|
332
|
+
initial_interval: Some(prost_dur!(from_millis(65))),
|
|
332
333
|
// This will make the second backoff 65 seconds, plenty to use timer
|
|
333
334
|
backoff_coefficient: 1_000.,
|
|
334
|
-
maximum_interval: Some(
|
|
335
|
+
maximum_interval: Some(prost_dur!(from_secs(600))),
|
|
335
336
|
maximum_attempts: 3,
|
|
336
337
|
non_retryable_error_types: vec![],
|
|
337
338
|
},
|
|
@@ -399,11 +400,10 @@ async fn local_act_null_result() {
|
|
|
399
400
|
|
|
400
401
|
#[tokio::test]
|
|
401
402
|
async fn query_during_wft_heartbeat_doesnt_accidentally_fail_to_continue_heartbeat() {
|
|
402
|
-
crate::telemetry::test_telem_console();
|
|
403
403
|
let wfid = "fake_wf_id";
|
|
404
404
|
let mut t = TestHistoryBuilder::default();
|
|
405
405
|
let mut wes_short_wft_timeout = default_wes_attribs();
|
|
406
|
-
wes_short_wft_timeout.workflow_task_timeout = Some(
|
|
406
|
+
wes_short_wft_timeout.workflow_task_timeout = Some(prost_dur!(from_millis(200)));
|
|
407
407
|
t.add(
|
|
408
408
|
EventType::WorkflowExecutionStarted,
|
|
409
409
|
wes_short_wft_timeout.into(),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
+
prost_dur,
|
|
2
3
|
test_help::{
|
|
3
4
|
build_fake_worker, build_mock_pollers, canned_histories, mock_manual_poller, mock_worker,
|
|
4
5
|
MockPollCfg, MockWorkerInputs, MocksHolder, ResponseType,
|
|
@@ -35,7 +36,7 @@ async fn after_shutdown_of_worker_get_shutdown_err() {
|
|
|
35
36
|
run_id.clone(),
|
|
36
37
|
workflow_command::Variant::StartTimer(StartTimer {
|
|
37
38
|
seq: 1,
|
|
38
|
-
start_to_fire_timeout: Some(
|
|
39
|
+
start_to_fire_timeout: Some(prost_dur!(from_secs(1))),
|
|
39
40
|
}),
|
|
40
41
|
))
|
|
41
42
|
.await
|
|
@@ -104,7 +105,7 @@ async fn worker_shutdown_during_poll_doesnt_deadlock() {
|
|
|
104
105
|
mock_client
|
|
105
106
|
.expect_complete_workflow_task()
|
|
106
107
|
.returning(|_| Ok(RespondWorkflowTaskCompletedResponse::default()));
|
|
107
|
-
let worker = mock_worker(MocksHolder::from_mock_worker(mock_client
|
|
108
|
+
let worker = mock_worker(MocksHolder::from_mock_worker(mock_client, mw));
|
|
108
109
|
let pollfut = worker.poll_workflow_activation();
|
|
109
110
|
let shutdownfut = async {
|
|
110
111
|
worker.shutdown().await;
|
|
@@ -15,7 +15,7 @@ use crate::{
|
|
|
15
15
|
use futures::{stream, FutureExt};
|
|
16
16
|
use rstest::{fixture, rstest};
|
|
17
17
|
use std::{
|
|
18
|
-
collections::VecDeque,
|
|
18
|
+
collections::{HashMap, VecDeque},
|
|
19
19
|
sync::{
|
|
20
20
|
atomic::{AtomicU64, Ordering},
|
|
21
21
|
Arc,
|
|
@@ -33,11 +33,15 @@ use temporal_sdk_core_protos::{
|
|
|
33
33
|
},
|
|
34
34
|
workflow_commands::{
|
|
35
35
|
ActivityCancellationType, CancelTimer, CompleteWorkflowExecution,
|
|
36
|
-
FailWorkflowExecution, RequestCancelActivity,
|
|
36
|
+
ContinueAsNewWorkflowExecution, FailWorkflowExecution, RequestCancelActivity,
|
|
37
|
+
ScheduleActivity,
|
|
37
38
|
},
|
|
38
39
|
workflow_completion::WorkflowActivationCompletion,
|
|
39
40
|
},
|
|
41
|
+
default_wes_attribs,
|
|
40
42
|
temporal::api::{
|
|
43
|
+
command::v1::command::Attributes,
|
|
44
|
+
common::v1::{Payload, RetryPolicy},
|
|
41
45
|
enums::v1::{EventType, WorkflowTaskFailedCause},
|
|
42
46
|
failure::v1::Failure,
|
|
43
47
|
history::v1::{history_event, TimerFiredEventAttributes},
|
|
@@ -2000,3 +2004,67 @@ async fn no_race_acquiring_permits() {
|
|
|
2000
2004
|
};
|
|
2001
2005
|
join!(poll_1_f, poll_2_f, other_f);
|
|
2002
2006
|
}
|
|
2007
|
+
|
|
2008
|
+
#[tokio::test]
|
|
2009
|
+
async fn continue_as_new_preserves_some_values() {
|
|
2010
|
+
let wfid = "fake_wf_id";
|
|
2011
|
+
let memo = HashMap::<String, Payload>::from([("enchi".to_string(), b"cat".into())]).into();
|
|
2012
|
+
let search = HashMap::<String, Payload>::from([("noisy".to_string(), b"kitty".into())]).into();
|
|
2013
|
+
let retry_policy = RetryPolicy {
|
|
2014
|
+
backoff_coefficient: 13.37,
|
|
2015
|
+
..Default::default()
|
|
2016
|
+
};
|
|
2017
|
+
let mut wes_attrs = default_wes_attribs();
|
|
2018
|
+
wes_attrs.memo = Some(memo);
|
|
2019
|
+
wes_attrs.search_attributes = Some(search);
|
|
2020
|
+
wes_attrs.retry_policy = Some(retry_policy);
|
|
2021
|
+
let mut mock_client = mock_workflow_client();
|
|
2022
|
+
let hist = {
|
|
2023
|
+
let mut t = TestHistoryBuilder::default();
|
|
2024
|
+
t.add(
|
|
2025
|
+
EventType::WorkflowExecutionStarted,
|
|
2026
|
+
wes_attrs.clone().into(),
|
|
2027
|
+
);
|
|
2028
|
+
t.add_full_wf_task();
|
|
2029
|
+
t
|
|
2030
|
+
};
|
|
2031
|
+
mock_client
|
|
2032
|
+
.expect_poll_workflow_task()
|
|
2033
|
+
.returning(move |_, _| {
|
|
2034
|
+
Ok(hist_to_poll_resp(
|
|
2035
|
+
&hist,
|
|
2036
|
+
wfid.to_owned(),
|
|
2037
|
+
ResponseType::AllHistory,
|
|
2038
|
+
TEST_Q.to_string(),
|
|
2039
|
+
)
|
|
2040
|
+
.resp)
|
|
2041
|
+
});
|
|
2042
|
+
mock_client
|
|
2043
|
+
.expect_complete_workflow_task()
|
|
2044
|
+
.returning(move |mut c| {
|
|
2045
|
+
let can_cmd = c.commands.pop().unwrap().attributes.unwrap();
|
|
2046
|
+
if let Attributes::ContinueAsNewWorkflowExecutionCommandAttributes(a) = can_cmd {
|
|
2047
|
+
assert_eq!(a.workflow_type.unwrap().name, "meow");
|
|
2048
|
+
assert_eq!(a.memo, wes_attrs.memo);
|
|
2049
|
+
assert_eq!(a.search_attributes, wes_attrs.search_attributes);
|
|
2050
|
+
assert_eq!(a.retry_policy, wes_attrs.retry_policy);
|
|
2051
|
+
} else {
|
|
2052
|
+
panic!("Wrong attributes type");
|
|
2053
|
+
}
|
|
2054
|
+
Ok(Default::default())
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
let worker = Worker::new_test(test_worker_cfg().build().unwrap(), mock_client);
|
|
2058
|
+
let r = worker.poll_workflow_activation().await.unwrap();
|
|
2059
|
+
worker
|
|
2060
|
+
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
2061
|
+
r.run_id,
|
|
2062
|
+
ContinueAsNewWorkflowExecution {
|
|
2063
|
+
workflow_type: "meow".to_string(),
|
|
2064
|
+
..Default::default()
|
|
2065
|
+
}
|
|
2066
|
+
.into(),
|
|
2067
|
+
))
|
|
2068
|
+
.await
|
|
2069
|
+
.unwrap();
|
|
2070
|
+
}
|