@temporalio/core-bridge 1.6.0 → 1.7.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 +520 -456
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +8 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +1 -1
- package/sdk-core/.github/workflows/heavy.yml +1 -0
- package/sdk-core/README.md +13 -7
- package/sdk-core/client/src/lib.rs +27 -9
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +3 -3
- package/sdk-core/core/Cargo.toml +3 -4
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +197 -18
- package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +212 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
- package/sdk-core/core/src/core_tests/queries.rs +32 -14
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
- package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
- package/sdk-core/core/src/internal_flags.rs +141 -0
- package/sdk-core/core/src/lib.rs +14 -9
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +38 -14
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +65 -13
- 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 +122 -6
- package/sdk-core/core/src/worker/activities.rs +347 -173
- 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 +137 -44
- package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
- package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
- package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
- package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
- package/sdk-core/core-api/Cargo.toml +0 -1
- package/sdk-core/core-api/src/lib.rs +13 -7
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
- package/sdk-core/histories/ends_empty_wft_complete.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 +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- 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 +65 -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/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +21 -5
- 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 +9 -3
- package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
- package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/lib.rs +32 -5
- package/sdk-core/tests/heavy_tests.rs +10 -43
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
- package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
- 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 +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
- package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
- package/sdk-core/tests/main.rs +16 -25
- package/sdk-core/tests/runner.rs +11 -9
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
|
@@ -34,6 +34,7 @@ use temporal_sdk_core::{
|
|
|
34
34
|
replay::HistoryForReplay,
|
|
35
35
|
ClientOptions, ClientOptionsBuilder, CoreRuntime, WorkerConfig, WorkerConfigBuilder,
|
|
36
36
|
};
|
|
37
|
+
use temporal_sdk_core_api::errors::{PollActivityError, PollWfError};
|
|
37
38
|
use temporal_sdk_core_api::{
|
|
38
39
|
telemetry::{
|
|
39
40
|
Logger, MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
|
|
@@ -50,6 +51,7 @@ use temporal_sdk_core_protos::{
|
|
|
50
51
|
workflow_completion::WorkflowActivationCompletion,
|
|
51
52
|
},
|
|
52
53
|
temporal::api::{common::v1::Payload, history::v1::History},
|
|
54
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
53
55
|
};
|
|
54
56
|
use tokio::sync::{mpsc::unbounded_channel, OnceCell};
|
|
55
57
|
use url::Url;
|
|
@@ -58,8 +60,8 @@ pub const NAMESPACE: &str = "default";
|
|
|
58
60
|
pub const TEST_Q: &str = "q";
|
|
59
61
|
/// The env var used to specify where the integ tests should point
|
|
60
62
|
pub const INTEG_SERVER_TARGET_ENV_VAR: &str = "TEMPORAL_SERVICE_ADDRESS";
|
|
61
|
-
/// This env var is set (to any value) if
|
|
62
|
-
pub const
|
|
63
|
+
/// This env var is set (to any value) if temporal CLI dev server is in use
|
|
64
|
+
pub const INTEG_TEMPORAL_DEV_SERVER_USED_ENV_VAR: &str = "INTEG_TEMPORAL_DEV_SERVER_ON";
|
|
63
65
|
/// This env var is set (to any value) if the test server is in use
|
|
64
66
|
pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
|
|
65
67
|
|
|
@@ -301,6 +303,11 @@ impl CoreWfStarter {
|
|
|
301
303
|
self
|
|
302
304
|
}
|
|
303
305
|
|
|
306
|
+
pub fn no_remote_activities(&mut self) -> &mut Self {
|
|
307
|
+
self.worker_config.no_remote_activities = true;
|
|
308
|
+
self
|
|
309
|
+
}
|
|
310
|
+
|
|
304
311
|
pub fn enable_wf_state_input_recording(&mut self) -> &mut Self {
|
|
305
312
|
let (ser_tx, ser_rx) = unbounded_channel();
|
|
306
313
|
let worker_cfg_clone = self.worker_config.clone();
|
|
@@ -569,7 +576,7 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
569
576
|
|
|
570
577
|
pub fn default_cached_download() -> EphemeralExe {
|
|
571
578
|
EphemeralExe::CachedDownload {
|
|
572
|
-
version: EphemeralExeVersion::
|
|
579
|
+
version: EphemeralExeVersion::SDKDefault {
|
|
573
580
|
sdk_name: "sdk-rust".to_string(),
|
|
574
581
|
sdk_version: "0.1.0".to_string(),
|
|
575
582
|
},
|
|
@@ -588,7 +595,7 @@ pub fn schedule_activity_cmd(
|
|
|
588
595
|
ScheduleActivity {
|
|
589
596
|
seq,
|
|
590
597
|
activity_id: activity_id.to_string(),
|
|
591
|
-
activity_type:
|
|
598
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
592
599
|
task_queue: task_q.to_owned(),
|
|
593
600
|
schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
594
601
|
start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
@@ -609,7 +616,7 @@ pub fn schedule_local_activity_cmd(
|
|
|
609
616
|
ScheduleLocalActivity {
|
|
610
617
|
seq,
|
|
611
618
|
activity_id: activity_id.to_string(),
|
|
612
|
-
activity_type:
|
|
619
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
613
620
|
schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
614
621
|
start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
615
622
|
schedule_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
@@ -680,3 +687,23 @@ where
|
|
|
680
687
|
.unwrap();
|
|
681
688
|
}
|
|
682
689
|
}
|
|
690
|
+
|
|
691
|
+
/// Initiate shutdown, drain the pollers, and wait for shutdown to complete.
|
|
692
|
+
pub async fn drain_pollers_and_shutdown(worker: &Arc<dyn CoreWorker>) {
|
|
693
|
+
worker.initiate_shutdown();
|
|
694
|
+
tokio::join!(
|
|
695
|
+
async {
|
|
696
|
+
assert!(matches!(
|
|
697
|
+
worker.poll_activity_task().await.unwrap_err(),
|
|
698
|
+
PollActivityError::ShutDown
|
|
699
|
+
));
|
|
700
|
+
},
|
|
701
|
+
async {
|
|
702
|
+
assert!(matches!(
|
|
703
|
+
worker.poll_workflow_activation().await.unwrap_err(),
|
|
704
|
+
PollWfError::ShutDown,
|
|
705
|
+
));
|
|
706
|
+
}
|
|
707
|
+
);
|
|
708
|
+
worker.shutdown().await;
|
|
709
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
use assert_matches::assert_matches;
|
|
2
1
|
use futures::{future::join_all, sink, stream::FuturesUnordered, StreamExt};
|
|
3
2
|
use std::time::{Duration, Instant};
|
|
4
3
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
|
|
5
4
|
use temporal_sdk::{ActContext, ActivityOptions, WfContext, WorkflowResult};
|
|
6
5
|
use temporal_sdk_core_protos::coresdk::{
|
|
7
|
-
|
|
8
|
-
workflow_commands::ActivityCancellationType, ActivityTaskCompletion, AsJsonPayloadExt,
|
|
6
|
+
workflow_commands::ActivityCancellationType, AsJsonPayloadExt,
|
|
9
7
|
};
|
|
10
8
|
use temporal_sdk_core_test_utils::{workflows::la_problem_workflow, CoreWfStarter};
|
|
11
9
|
|
|
@@ -25,18 +23,16 @@ async fn activity_load() {
|
|
|
25
23
|
|
|
26
24
|
let activity_id = "act-1";
|
|
27
25
|
let activity_timeout = Duration::from_secs(8);
|
|
28
|
-
let payload_dat = b"hello".to_vec();
|
|
29
26
|
let task_queue = starter.get_task_queue().to_owned();
|
|
30
27
|
|
|
31
|
-
let pd = payload_dat.clone();
|
|
32
28
|
let wf_fn = move |ctx: WfContext| {
|
|
33
29
|
let task_queue = task_queue.clone();
|
|
34
|
-
let
|
|
35
|
-
|
|
30
|
+
let payload = "yo".as_json_payload().unwrap();
|
|
36
31
|
async move {
|
|
37
32
|
let activity = ActivityOptions {
|
|
38
33
|
activity_id: Some(activity_id.to_string()),
|
|
39
34
|
activity_type: "test_activity".to_string(),
|
|
35
|
+
input: payload.clone(),
|
|
40
36
|
task_queue,
|
|
41
37
|
schedule_to_start_timeout: Some(activity_timeout),
|
|
42
38
|
start_to_close_timeout: Some(activity_timeout),
|
|
@@ -46,7 +42,7 @@ async fn activity_load() {
|
|
|
46
42
|
..Default::default()
|
|
47
43
|
};
|
|
48
44
|
let res = ctx.activity(activity).await.unwrap_ok_payload();
|
|
49
|
-
assert_eq!(res.data,
|
|
45
|
+
assert_eq!(res.data, payload.data);
|
|
50
46
|
Ok(().into())
|
|
51
47
|
}
|
|
52
48
|
};
|
|
@@ -54,6 +50,10 @@ async fn activity_load() {
|
|
|
54
50
|
let starting = Instant::now();
|
|
55
51
|
let wf_type = "activity_load";
|
|
56
52
|
worker.register_wf(wf_type.to_owned(), wf_fn);
|
|
53
|
+
worker.register_activity(
|
|
54
|
+
"test_activity",
|
|
55
|
+
|_ctx: ActContext, echo: String| async move { Ok(echo) },
|
|
56
|
+
);
|
|
57
57
|
join_all((0..CONCURRENCY).map(|i| {
|
|
58
58
|
let worker = &worker;
|
|
59
59
|
let wf_id = format!("activity_load_{i}");
|
|
@@ -73,42 +73,8 @@ async fn activity_load() {
|
|
|
73
73
|
dbg!(starting.elapsed());
|
|
74
74
|
|
|
75
75
|
let running = Instant::now();
|
|
76
|
-
let core = starter.get_worker().await;
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
let c2 = core.clone();
|
|
80
|
-
let all_acts = async move {
|
|
81
|
-
let mut act_complete_futs = vec![];
|
|
82
|
-
for _ in 0..CONCURRENCY {
|
|
83
|
-
let task = c2.poll_activity_task().await.unwrap();
|
|
84
|
-
assert_matches!(
|
|
85
|
-
task.variant,
|
|
86
|
-
Some(act_task::Variant::Start(ref start_activity)) => {
|
|
87
|
-
assert_eq!(start_activity.activity_type, "test_activity")
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
let pd = payload_dat.clone();
|
|
91
|
-
let core = c2.clone();
|
|
92
|
-
act_complete_futs.push(tokio::spawn(async move {
|
|
93
|
-
core.complete_activity_task(ActivityTaskCompletion {
|
|
94
|
-
task_token: task.task_token,
|
|
95
|
-
result: Some(ActivityExecutionResult::ok(pd.into())),
|
|
96
|
-
})
|
|
97
|
-
.await
|
|
98
|
-
.unwrap()
|
|
99
|
-
}));
|
|
100
|
-
}
|
|
101
|
-
join_all(act_complete_futs)
|
|
102
|
-
.await
|
|
103
|
-
.into_iter()
|
|
104
|
-
.for_each(|h| h.unwrap());
|
|
105
|
-
};
|
|
106
|
-
tokio::join! {
|
|
107
|
-
async {
|
|
108
|
-
worker.run_until_done().await.unwrap();
|
|
109
|
-
},
|
|
110
|
-
all_acts
|
|
111
|
-
};
|
|
77
|
+
worker.run_until_done().await.unwrap();
|
|
112
78
|
dbg!(running.elapsed());
|
|
113
79
|
}
|
|
114
80
|
|
|
@@ -262,6 +228,7 @@ pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()>
|
|
|
262
228
|
async fn can_paginate_long_history() {
|
|
263
229
|
let wf_name = "can_paginate_long_history";
|
|
264
230
|
let mut starter = CoreWfStarter::new(wf_name);
|
|
231
|
+
starter.no_remote_activities();
|
|
265
232
|
// Do not use sticky queues so we are forced to paginate once history gets long
|
|
266
233
|
starter.max_cached_workflows(0);
|
|
267
234
|
|
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
2
2
|
use temporal_client::{ClientOptionsBuilder, TestService, WorkflowService};
|
|
3
3
|
use temporal_sdk_core::ephemeral_server::{
|
|
4
|
-
EphemeralExe, EphemeralExeVersion, EphemeralServer,
|
|
5
|
-
TestServerConfigBuilder,
|
|
4
|
+
EphemeralExe, EphemeralExeVersion, EphemeralServer, TemporalDevServerConfigBuilder,
|
|
5
|
+
TemporaliteConfigBuilder, TestServerConfigBuilder,
|
|
6
6
|
};
|
|
7
7
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::DescribeNamespaceRequest;
|
|
8
8
|
use temporal_sdk_core_test_utils::{default_cached_download, NAMESPACE};
|
|
9
9
|
use url::Url;
|
|
10
10
|
|
|
11
|
+
#[tokio::test]
|
|
12
|
+
async fn temporal_cli_default() {
|
|
13
|
+
let config = TemporalDevServerConfigBuilder::default()
|
|
14
|
+
.exe(default_cached_download())
|
|
15
|
+
.build()
|
|
16
|
+
.unwrap();
|
|
17
|
+
let mut server = config.start_server().await.unwrap();
|
|
18
|
+
assert_ephemeral_server(&server).await;
|
|
19
|
+
server.shutdown().await.unwrap();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#[tokio::test]
|
|
23
|
+
async fn temporal_cli_fixed() {
|
|
24
|
+
let config = TemporalDevServerConfigBuilder::default()
|
|
25
|
+
.exe(fixed_cached_download("v0.4.0"))
|
|
26
|
+
.build()
|
|
27
|
+
.unwrap();
|
|
28
|
+
let mut server = config.start_server().await.unwrap();
|
|
29
|
+
assert_ephemeral_server(&server).await;
|
|
30
|
+
server.shutdown().await.unwrap();
|
|
31
|
+
}
|
|
32
|
+
|
|
11
33
|
#[tokio::test]
|
|
12
34
|
async fn temporalite_default() {
|
|
13
35
|
let config = TemporaliteConfigBuilder::default()
|
|
@@ -22,7 +44,7 @@ async fn temporalite_default() {
|
|
|
22
44
|
#[tokio::test]
|
|
23
45
|
async fn temporalite_fixed() {
|
|
24
46
|
let config = TemporaliteConfigBuilder::default()
|
|
25
|
-
.exe(fixed_cached_download("v0.
|
|
47
|
+
.exe(fixed_cached_download("v0.2.0"))
|
|
26
48
|
.build()
|
|
27
49
|
.unwrap();
|
|
28
50
|
let mut server = config.start_server().await.unwrap();
|
|
@@ -17,9 +17,11 @@ use temporal_sdk_core_protos::{
|
|
|
17
17
|
common::v1::{Payload, RetryPolicy},
|
|
18
18
|
enums::v1::TimeoutType,
|
|
19
19
|
},
|
|
20
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
20
21
|
};
|
|
21
22
|
use temporal_sdk_core_test_utils::{
|
|
22
|
-
init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter,
|
|
23
|
+
drain_pollers_and_shutdown, init_core_and_create_wf, schedule_activity_cmd, CoreWfStarter,
|
|
24
|
+
WorkerTestHelpers,
|
|
23
25
|
};
|
|
24
26
|
use tokio::time::sleep;
|
|
25
27
|
|
|
@@ -49,7 +51,7 @@ async fn activity_heartbeat() {
|
|
|
49
51
|
assert_matches!(
|
|
50
52
|
task.variant,
|
|
51
53
|
Some(activity_task::Variant::Start(start_activity)) => {
|
|
52
|
-
assert_eq!(start_activity.activity_type,
|
|
54
|
+
assert_eq!(start_activity.activity_type, DEFAULT_ACTIVITY_TYPE.to_string())
|
|
53
55
|
}
|
|
54
56
|
);
|
|
55
57
|
// Heartbeat timeout is set to 1 second, this loop is going to send heartbeat every 100ms.
|
|
@@ -169,7 +171,7 @@ async fn many_act_fails_with_heartbeats() {
|
|
|
169
171
|
},]
|
|
170
172
|
);
|
|
171
173
|
core.complete_execution(&task.run_id).await;
|
|
172
|
-
core
|
|
174
|
+
drain_pollers_and_shutdown(&core).await;
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
#[tokio::test]
|
|
@@ -1,18 +1,34 @@
|
|
|
1
|
-
use
|
|
2
|
-
use
|
|
3
|
-
use
|
|
4
|
-
use
|
|
5
|
-
use
|
|
1
|
+
use std::{sync::Arc, time::Duration};
|
|
2
|
+
use temporal_client::{WorkflowClientTrait, WorkflowOptions, WorkflowService};
|
|
3
|
+
use temporal_sdk_core::{init_worker, CoreRuntime};
|
|
4
|
+
use temporal_sdk_core_api::{telemetry::MetricsExporter, worker::WorkerConfigBuilder, Worker};
|
|
5
|
+
use temporal_sdk_core_protos::{
|
|
6
|
+
coresdk::{
|
|
7
|
+
activity_result::ActivityExecutionResult,
|
|
8
|
+
workflow_commands::{ScheduleActivity, ScheduleLocalActivity},
|
|
9
|
+
workflow_completion::WorkflowActivationCompletion,
|
|
10
|
+
ActivityTaskCompletion,
|
|
11
|
+
},
|
|
12
|
+
temporal::api::{enums::v1::WorkflowIdReusePolicy, workflowservice::v1::ListNamespacesRequest},
|
|
13
|
+
};
|
|
14
|
+
use temporal_sdk_core_test_utils::{get_integ_server_options, get_integ_telem_options, NAMESPACE};
|
|
15
|
+
use tokio::sync::Barrier;
|
|
16
|
+
|
|
17
|
+
static ANY_PORT: &str = "127.0.0.1:0";
|
|
18
|
+
|
|
19
|
+
async fn get_text(endpoint: String) -> String {
|
|
20
|
+
reqwest::get(endpoint).await.unwrap().text().await.unwrap()
|
|
21
|
+
}
|
|
6
22
|
|
|
7
23
|
#[tokio::test]
|
|
8
24
|
async fn prometheus_metrics_exported() {
|
|
9
25
|
let mut telemopts = get_integ_telem_options();
|
|
10
|
-
|
|
11
|
-
telemopts.metrics = Some(MetricsExporter::Prometheus(addr.parse().unwrap()));
|
|
26
|
+
telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
|
|
12
27
|
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
28
|
+
let addr = rt.telemetry().prom_port().unwrap();
|
|
13
29
|
let opts = get_integ_server_options();
|
|
14
30
|
let mut raw_client = opts
|
|
15
|
-
.connect_no_namespace(rt.metric_meter(), None)
|
|
31
|
+
.connect_no_namespace(rt.metric_meter().as_deref(), None)
|
|
16
32
|
.await
|
|
17
33
|
.unwrap();
|
|
18
34
|
assert!(raw_client.get_client().capabilities().is_some());
|
|
@@ -22,16 +38,202 @@ async fn prometheus_metrics_exported() {
|
|
|
22
38
|
.await
|
|
23
39
|
.unwrap();
|
|
24
40
|
|
|
25
|
-
let body =
|
|
26
|
-
.await
|
|
27
|
-
.unwrap()
|
|
28
|
-
.text()
|
|
29
|
-
.await
|
|
30
|
-
.unwrap();
|
|
41
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
31
42
|
assert!(body.contains(
|
|
32
|
-
"
|
|
43
|
+
"temporal_request_latency_count{operation=\"ListNamespaces\",service_name=\"temporal-core-sdk\"} 1"
|
|
33
44
|
));
|
|
34
45
|
assert!(body.contains(
|
|
35
|
-
"
|
|
46
|
+
"temporal_request_latency_count{operation=\"GetSystemInfo\",service_name=\"temporal-core-sdk\"} 1"
|
|
36
47
|
));
|
|
37
48
|
}
|
|
49
|
+
|
|
50
|
+
#[tokio::test]
|
|
51
|
+
async fn one_slot_worker_reports_available_slot() {
|
|
52
|
+
let mut telemopts = get_integ_telem_options();
|
|
53
|
+
let tq = "one_slot_worker_tq";
|
|
54
|
+
telemopts.metrics = Some(MetricsExporter::Prometheus(ANY_PORT.parse().unwrap()));
|
|
55
|
+
let rt = CoreRuntime::new_assume_tokio(telemopts).unwrap();
|
|
56
|
+
let addr = rt.telemetry().prom_port().unwrap();
|
|
57
|
+
|
|
58
|
+
let worker_cfg = WorkerConfigBuilder::default()
|
|
59
|
+
.namespace(NAMESPACE)
|
|
60
|
+
.task_queue(tq)
|
|
61
|
+
.worker_build_id("test_build_id")
|
|
62
|
+
.max_cached_workflows(1_usize)
|
|
63
|
+
.max_outstanding_activities(1_usize)
|
|
64
|
+
.max_outstanding_local_activities(1_usize)
|
|
65
|
+
.max_outstanding_workflow_tasks(1_usize)
|
|
66
|
+
.build()
|
|
67
|
+
.unwrap();
|
|
68
|
+
|
|
69
|
+
let client = Arc::new(
|
|
70
|
+
get_integ_server_options()
|
|
71
|
+
.connect(worker_cfg.namespace.clone(), None, None)
|
|
72
|
+
.await
|
|
73
|
+
.expect("Must connect"),
|
|
74
|
+
);
|
|
75
|
+
let worker = init_worker(&rt, worker_cfg, client.clone()).expect("Worker inits cleanly");
|
|
76
|
+
let wf_task_barr = Barrier::new(2);
|
|
77
|
+
let act_task_barr = Barrier::new(2);
|
|
78
|
+
|
|
79
|
+
let wf_polling = async {
|
|
80
|
+
let task = worker.poll_workflow_activation().await.unwrap();
|
|
81
|
+
wf_task_barr.wait().await;
|
|
82
|
+
wf_task_barr.wait().await;
|
|
83
|
+
worker
|
|
84
|
+
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
85
|
+
task.run_id,
|
|
86
|
+
ScheduleActivity {
|
|
87
|
+
seq: 1,
|
|
88
|
+
activity_id: "1".to_string(),
|
|
89
|
+
activity_type: "test_act".to_string(),
|
|
90
|
+
task_queue: tq.to_string(),
|
|
91
|
+
start_to_close_timeout: Some(prost_dur!(from_secs(30))),
|
|
92
|
+
..Default::default()
|
|
93
|
+
}
|
|
94
|
+
.into(),
|
|
95
|
+
))
|
|
96
|
+
.await
|
|
97
|
+
.unwrap();
|
|
98
|
+
wf_task_barr.wait().await;
|
|
99
|
+
|
|
100
|
+
let task = worker.poll_workflow_activation().await.unwrap();
|
|
101
|
+
worker
|
|
102
|
+
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
103
|
+
task.run_id,
|
|
104
|
+
ScheduleLocalActivity {
|
|
105
|
+
seq: 2,
|
|
106
|
+
activity_id: "2".to_string(),
|
|
107
|
+
activity_type: "test_act".to_string(),
|
|
108
|
+
start_to_close_timeout: Some(prost_dur!(from_secs(30))),
|
|
109
|
+
..Default::default()
|
|
110
|
+
}
|
|
111
|
+
.into(),
|
|
112
|
+
))
|
|
113
|
+
.await
|
|
114
|
+
.unwrap();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
let act_polling = async {
|
|
118
|
+
let task = worker.poll_activity_task().await.unwrap();
|
|
119
|
+
act_task_barr.wait().await;
|
|
120
|
+
worker
|
|
121
|
+
.complete_activity_task(ActivityTaskCompletion {
|
|
122
|
+
task_token: task.task_token,
|
|
123
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
124
|
+
})
|
|
125
|
+
.await
|
|
126
|
+
.unwrap();
|
|
127
|
+
act_task_barr.wait().await;
|
|
128
|
+
|
|
129
|
+
let task = worker.poll_activity_task().await.unwrap();
|
|
130
|
+
act_task_barr.wait().await;
|
|
131
|
+
act_task_barr.wait().await;
|
|
132
|
+
worker
|
|
133
|
+
.complete_activity_task(ActivityTaskCompletion {
|
|
134
|
+
task_token: task.task_token,
|
|
135
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
136
|
+
})
|
|
137
|
+
.await
|
|
138
|
+
.unwrap();
|
|
139
|
+
act_task_barr.wait().await;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
let testing = async {
|
|
143
|
+
// Wait just a beat for the poller to initiate
|
|
144
|
+
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
145
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
146
|
+
assert!(body.contains(&format!(
|
|
147
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
148
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
149
|
+
worker_type=\"WorkflowWorker\"}} 1"
|
|
150
|
+
)));
|
|
151
|
+
|
|
152
|
+
// Start a workflow so that a task will get delivered
|
|
153
|
+
client
|
|
154
|
+
.start_workflow(
|
|
155
|
+
vec![],
|
|
156
|
+
tq.to_owned(),
|
|
157
|
+
"one_slot_metric_test".to_owned(),
|
|
158
|
+
"whatever".to_string(),
|
|
159
|
+
None,
|
|
160
|
+
WorkflowOptions {
|
|
161
|
+
id_reuse_policy: WorkflowIdReusePolicy::TerminateIfRunning,
|
|
162
|
+
execution_timeout: Some(Duration::from_secs(5)),
|
|
163
|
+
..Default::default()
|
|
164
|
+
},
|
|
165
|
+
)
|
|
166
|
+
.await
|
|
167
|
+
.unwrap();
|
|
168
|
+
|
|
169
|
+
wf_task_barr.wait().await;
|
|
170
|
+
|
|
171
|
+
// At this point the workflow task is outstanding, so there should be 0 slots, and
|
|
172
|
+
// the activities haven't started, so there should be 1 each.
|
|
173
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
174
|
+
assert!(body.contains(&format!(
|
|
175
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
176
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
177
|
+
worker_type=\"WorkflowWorker\"}} 0"
|
|
178
|
+
)));
|
|
179
|
+
assert!(body.contains(&format!(
|
|
180
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
181
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
182
|
+
worker_type=\"ActivityWorker\"}} 1"
|
|
183
|
+
)));
|
|
184
|
+
assert!(body.contains(&format!(
|
|
185
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
186
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
187
|
+
worker_type=\"LocalActivityWorker\"}} 1"
|
|
188
|
+
)));
|
|
189
|
+
|
|
190
|
+
// Now we allow the complete to proceed. Once it goes through, there should be 1 WFT slot
|
|
191
|
+
// open but 0 activity slots
|
|
192
|
+
wf_task_barr.wait().await;
|
|
193
|
+
wf_task_barr.wait().await;
|
|
194
|
+
// Sometimes the recording takes an extra bit. 🤷
|
|
195
|
+
tokio::time::sleep(Duration::from_millis(100)).await;
|
|
196
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
197
|
+
assert!(body.contains(&format!(
|
|
198
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
199
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
200
|
+
worker_type=\"WorkflowWorker\"}} 1"
|
|
201
|
+
)));
|
|
202
|
+
assert!(body.contains(&format!(
|
|
203
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
204
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
205
|
+
worker_type=\"ActivityWorker\"}} 0"
|
|
206
|
+
)));
|
|
207
|
+
|
|
208
|
+
// Now complete the activity and watch it go up
|
|
209
|
+
act_task_barr.wait().await;
|
|
210
|
+
// Wait for completion to finish
|
|
211
|
+
act_task_barr.wait().await;
|
|
212
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
213
|
+
assert!(body.contains(&format!(
|
|
214
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
215
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
216
|
+
worker_type=\"ActivityWorker\"}} 1"
|
|
217
|
+
)));
|
|
218
|
+
|
|
219
|
+
// Proceed to local activity command
|
|
220
|
+
act_task_barr.wait().await;
|
|
221
|
+
// Ensure that, once we have the LA task, slots are 0
|
|
222
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
223
|
+
assert!(body.contains(&format!(
|
|
224
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
225
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
226
|
+
worker_type=\"LocalActivityWorker\"}} 0"
|
|
227
|
+
)));
|
|
228
|
+
// When completion is done, we have 1 again
|
|
229
|
+
act_task_barr.wait().await;
|
|
230
|
+
act_task_barr.wait().await;
|
|
231
|
+
let body = get_text(format!("http://{addr}/metrics")).await;
|
|
232
|
+
assert!(body.contains(&format!(
|
|
233
|
+
"temporal_worker_task_slots_available{{namespace=\"{NAMESPACE}\",\
|
|
234
|
+
service_name=\"temporal-core-sdk\",task_queue=\"one_slot_worker_tq\",\
|
|
235
|
+
worker_type=\"LocalActivityWorker\"}} 1"
|
|
236
|
+
)));
|
|
237
|
+
};
|
|
238
|
+
tokio::join!(wf_polling, act_polling, testing);
|
|
239
|
+
}
|
|
@@ -40,15 +40,10 @@ async fn out_of_order_completion_doesnt_hang() {
|
|
|
40
40
|
)
|
|
41
41
|
.await
|
|
42
42
|
.unwrap();
|
|
43
|
-
// Poll activity and verify that it's been scheduled
|
|
44
|
-
//
|
|
43
|
+
// Poll activity and verify that it's been scheduled, we don't expect to complete it in this
|
|
44
|
+
// test as activity is try-cancelled.
|
|
45
45
|
let activity_task = core.poll_activity_task().await.unwrap();
|
|
46
|
-
assert_matches!(
|
|
47
|
-
activity_task.variant,
|
|
48
|
-
Some(act_task::Variant::Start(start_activity)) => {
|
|
49
|
-
assert_eq!(start_activity.activity_type, "test_activity".to_string())
|
|
50
|
-
}
|
|
51
|
-
);
|
|
46
|
+
assert_matches!(activity_task.variant, Some(act_task::Variant::Start(_)));
|
|
52
47
|
// Poll workflow task and verify that activity has failed.
|
|
53
48
|
let task = core.poll_workflow_activation().await.unwrap();
|
|
54
49
|
assert_matches!(
|
|
@@ -10,7 +10,9 @@ use temporal_sdk_core_protos::{
|
|
|
10
10
|
},
|
|
11
11
|
temporal::api::{failure::v1::Failure, query::v1::WorkflowQuery},
|
|
12
12
|
};
|
|
13
|
-
use temporal_sdk_core_test_utils::{
|
|
13
|
+
use temporal_sdk_core_test_utils::{
|
|
14
|
+
drain_pollers_and_shutdown, init_core_and_create_wf, WorkerTestHelpers,
|
|
15
|
+
};
|
|
14
16
|
|
|
15
17
|
#[tokio::test]
|
|
16
18
|
async fn simple_query_legacy() {
|
|
@@ -205,7 +207,7 @@ async fn query_after_execution_complete(#[case] do_evict: bool) {
|
|
|
205
207
|
query_futs.push(do_workflow(true).map(|_| ()).boxed());
|
|
206
208
|
}
|
|
207
209
|
while query_futs.next().await.is_some() {}
|
|
208
|
-
core
|
|
210
|
+
drain_pollers_and_shutdown(core).await;
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
#[tokio::test]
|
|
@@ -8,7 +8,8 @@ use temporal_sdk_core_protos::coresdk::workflow_activation::{
|
|
|
8
8
|
workflow_activation_job, WorkflowActivationJob,
|
|
9
9
|
};
|
|
10
10
|
use temporal_sdk_core_test_utils::{
|
|
11
|
-
get_integ_server_options, CoreWfStarter, WorkerTestHelpers,
|
|
11
|
+
drain_pollers_and_shutdown, get_integ_server_options, CoreWfStarter, WorkerTestHelpers,
|
|
12
|
+
NAMESPACE,
|
|
12
13
|
};
|
|
13
14
|
use tokio::time::sleep;
|
|
14
15
|
|
|
@@ -51,29 +52,39 @@ async fn client_list_open_closed_workflow_executions() {
|
|
|
51
52
|
|
|
52
53
|
// Complete workflow
|
|
53
54
|
core.complete_execution(&task.run_id).await;
|
|
54
|
-
core
|
|
55
|
+
drain_pollers_and_shutdown(&core).await;
|
|
55
56
|
|
|
56
|
-
// List above CLOSED workflow
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
// List above CLOSED workflow. Visibility doesn't always update immediately so we give this a
|
|
58
|
+
// few tries.
|
|
59
|
+
let mut passed = false;
|
|
60
|
+
for _ in 1..=5 {
|
|
61
|
+
let closed_workflows = client
|
|
62
|
+
.list_closed_workflow_executions(
|
|
63
|
+
1,
|
|
64
|
+
Default::default(),
|
|
65
|
+
Some(StartTimeFilter {
|
|
66
|
+
earliest_time: Some(earliest).and_then(|t| t.try_into().ok()),
|
|
67
|
+
latest_time: Some(latest).and_then(|t| t.try_into().ok()),
|
|
68
|
+
}),
|
|
69
|
+
Some(ListClosedFilters::ExecutionFilter(
|
|
70
|
+
WorkflowExecutionFilter {
|
|
71
|
+
workflow_id: wf_name.clone(),
|
|
72
|
+
run_id: run_id.clone(),
|
|
73
|
+
},
|
|
74
|
+
)),
|
|
75
|
+
)
|
|
76
|
+
.await
|
|
77
|
+
.unwrap();
|
|
78
|
+
if closed_workflows.executions.len() == 1 {
|
|
79
|
+
let workflow = &closed_workflows.executions[0];
|
|
80
|
+
if workflow.execution.as_ref().unwrap().workflow_id == wf_name {
|
|
81
|
+
passed = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
sleep(Duration::from_millis(100)).await;
|
|
86
|
+
}
|
|
87
|
+
assert!(passed);
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
#[tokio::test]
|