@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
|
@@ -23,6 +23,6 @@ async fn main() -> Result<(), anyhow::Error> {
|
|
|
23
23
|
.expect("history field must be populated");
|
|
24
24
|
// Serialize history to file
|
|
25
25
|
let byteified = hist.encode_to_vec();
|
|
26
|
-
tokio::fs::write(format!("{}_history.bin"
|
|
26
|
+
tokio::fs::write(format!("{wf_id}_history.bin"), &byteified).await?;
|
|
27
27
|
Ok(())
|
|
28
28
|
}
|
|
@@ -5,8 +5,14 @@
|
|
|
5
5
|
extern crate tracing;
|
|
6
6
|
|
|
7
7
|
pub mod canned_histories;
|
|
8
|
+
pub mod wf_input_saver;
|
|
9
|
+
pub mod workflows;
|
|
8
10
|
|
|
9
|
-
use crate::
|
|
11
|
+
use crate::{
|
|
12
|
+
stream::{Stream, TryStreamExt},
|
|
13
|
+
wf_input_saver::stream_to_file,
|
|
14
|
+
};
|
|
15
|
+
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
10
16
|
use futures::{future, stream, stream::FuturesUnordered, StreamExt};
|
|
11
17
|
use parking_lot::Mutex;
|
|
12
18
|
use prost::Message;
|
|
@@ -28,6 +34,7 @@ use temporal_sdk_core::{
|
|
|
28
34
|
replay::HistoryForReplay,
|
|
29
35
|
ClientOptions, ClientOptionsBuilder, CoreRuntime, WorkerConfig, WorkerConfigBuilder,
|
|
30
36
|
};
|
|
37
|
+
use temporal_sdk_core_api::errors::{PollActivityError, PollWfError};
|
|
31
38
|
use temporal_sdk_core_api::{
|
|
32
39
|
telemetry::{
|
|
33
40
|
Logger, MetricsExporter, OtelCollectorOptions, TelemetryOptions, TelemetryOptionsBuilder,
|
|
@@ -44,16 +51,17 @@ use temporal_sdk_core_protos::{
|
|
|
44
51
|
workflow_completion::WorkflowActivationCompletion,
|
|
45
52
|
},
|
|
46
53
|
temporal::api::{common::v1::Payload, history::v1::History},
|
|
54
|
+
DEFAULT_ACTIVITY_TYPE,
|
|
47
55
|
};
|
|
48
|
-
use tokio::sync::OnceCell;
|
|
56
|
+
use tokio::sync::{mpsc::unbounded_channel, OnceCell};
|
|
49
57
|
use url::Url;
|
|
50
58
|
|
|
51
59
|
pub const NAMESPACE: &str = "default";
|
|
52
60
|
pub const TEST_Q: &str = "q";
|
|
53
61
|
/// The env var used to specify where the integ tests should point
|
|
54
62
|
pub const INTEG_SERVER_TARGET_ENV_VAR: &str = "TEMPORAL_SERVICE_ADDRESS";
|
|
55
|
-
/// This env var is set (to any value) if
|
|
56
|
-
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";
|
|
57
65
|
/// This env var is set (to any value) if the test server is in use
|
|
58
66
|
pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
|
|
59
67
|
|
|
@@ -61,6 +69,15 @@ pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
|
|
|
61
69
|
const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
|
|
62
70
|
/// If set, enable direct scraping of prom metrics on the specified port
|
|
63
71
|
const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
|
|
72
|
+
#[macro_export]
|
|
73
|
+
macro_rules! prost_dur {
|
|
74
|
+
($dur_call:ident $args:tt) => {
|
|
75
|
+
std::time::Duration::$dur_call$args
|
|
76
|
+
.try_into()
|
|
77
|
+
.expect("test duration fits")
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
/// Create a worker instance which will use the provided test name to base the task queue and wf id
|
|
65
82
|
/// upon. Returns the instance and the task queue name (which is also the workflow id).
|
|
66
83
|
pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
|
|
@@ -82,6 +99,7 @@ pub fn init_core_replay_stream<I>(test_name: &str, histories: I) -> Arc<dyn Core
|
|
|
82
99
|
where
|
|
83
100
|
I: Stream<Item = HistoryForReplay> + Send + 'static,
|
|
84
101
|
{
|
|
102
|
+
init_integ_telem();
|
|
85
103
|
let worker_cfg = WorkerConfigBuilder::default()
|
|
86
104
|
.namespace(NAMESPACE)
|
|
87
105
|
.task_queue(test_name)
|
|
@@ -134,7 +152,8 @@ pub struct CoreWfStarter {
|
|
|
134
152
|
/// Used for both the task queue and workflow id
|
|
135
153
|
task_queue_name: String,
|
|
136
154
|
pub worker_config: WorkerConfig,
|
|
137
|
-
|
|
155
|
+
/// Options to use when starting workflow(s)
|
|
156
|
+
pub workflow_options: WorkflowOptions,
|
|
138
157
|
initted_worker: OnceCell<InitializedWorker>,
|
|
139
158
|
}
|
|
140
159
|
struct InitializedWorker {
|
|
@@ -144,14 +163,10 @@ struct InitializedWorker {
|
|
|
144
163
|
|
|
145
164
|
impl CoreWfStarter {
|
|
146
165
|
pub fn new(test_name: &str) -> Self {
|
|
147
|
-
let rand_bytes: Vec<u8> = rand::thread_rng().sample_iter(&Standard).take(6).collect();
|
|
148
|
-
let task_q_salt = base64::encode(rand_bytes);
|
|
149
|
-
let task_queue = format!("{}_{}", test_name, task_q_salt);
|
|
150
|
-
Self::new_tq_name(&task_queue)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
pub fn new_tq_name(task_queue: &str) -> Self {
|
|
154
166
|
init_integ_telem();
|
|
167
|
+
let rand_bytes: Vec<u8> = rand::thread_rng().sample_iter(&Standard).take(6).collect();
|
|
168
|
+
let task_q_salt = BASE64_STANDARD.encode(rand_bytes);
|
|
169
|
+
let task_queue = format!("{test_name}_{task_q_salt}");
|
|
155
170
|
Self {
|
|
156
171
|
task_queue_name: task_queue.to_owned(),
|
|
157
172
|
worker_config: WorkerConfigBuilder::default()
|
|
@@ -161,8 +176,8 @@ impl CoreWfStarter {
|
|
|
161
176
|
.max_cached_workflows(1000_usize)
|
|
162
177
|
.build()
|
|
163
178
|
.unwrap(),
|
|
164
|
-
wft_timeout: None,
|
|
165
179
|
initted_worker: OnceCell::new(),
|
|
180
|
+
workflow_options: Default::default(),
|
|
166
181
|
}
|
|
167
182
|
}
|
|
168
183
|
|
|
@@ -189,13 +204,27 @@ impl CoreWfStarter {
|
|
|
189
204
|
}
|
|
190
205
|
|
|
191
206
|
/// Start the workflow defined by the builder and return run id
|
|
192
|
-
pub async fn start_wf(&self) -> String {
|
|
193
|
-
self.start_wf_with_id(self.task_queue_name.clone()
|
|
207
|
+
pub async fn start_wf(&mut self) -> String {
|
|
208
|
+
self.start_wf_with_id(self.task_queue_name.clone()).await
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
pub async fn start_with_worker(
|
|
212
|
+
&self,
|
|
213
|
+
wf_name: impl Into<String>,
|
|
214
|
+
worker: &mut TestWorker,
|
|
215
|
+
) -> String {
|
|
216
|
+
worker
|
|
217
|
+
.submit_wf(
|
|
218
|
+
self.task_queue_name.clone(),
|
|
219
|
+
wf_name.into(),
|
|
220
|
+
vec![],
|
|
221
|
+
self.workflow_options.clone(),
|
|
222
|
+
)
|
|
194
223
|
.await
|
|
224
|
+
.unwrap()
|
|
195
225
|
}
|
|
196
226
|
|
|
197
|
-
pub async fn start_wf_with_id(&self, workflow_id: String
|
|
198
|
-
opts.task_timeout = opts.task_timeout.or(self.wft_timeout);
|
|
227
|
+
pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
|
|
199
228
|
self.initted_worker
|
|
200
229
|
.get()
|
|
201
230
|
.expect(
|
|
@@ -209,7 +238,7 @@ impl CoreWfStarter {
|
|
|
209
238
|
workflow_id,
|
|
210
239
|
self.task_queue_name.clone(),
|
|
211
240
|
None,
|
|
212
|
-
|
|
241
|
+
self.workflow_options.clone(),
|
|
213
242
|
)
|
|
214
243
|
.await
|
|
215
244
|
.unwrap()
|
|
@@ -274,8 +303,18 @@ impl CoreWfStarter {
|
|
|
274
303
|
self
|
|
275
304
|
}
|
|
276
305
|
|
|
277
|
-
pub fn
|
|
278
|
-
self.
|
|
306
|
+
pub fn no_remote_activities(&mut self) -> &mut Self {
|
|
307
|
+
self.worker_config.no_remote_activities = true;
|
|
308
|
+
self
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
pub fn enable_wf_state_input_recording(&mut self) -> &mut Self {
|
|
312
|
+
let (ser_tx, ser_rx) = unbounded_channel();
|
|
313
|
+
let worker_cfg_clone = self.worker_config.clone();
|
|
314
|
+
tokio::spawn(async move {
|
|
315
|
+
stream_to_file(&worker_cfg_clone, ser_rx).await.unwrap();
|
|
316
|
+
});
|
|
317
|
+
self.worker_config.wf_state_inputs = Some(ser_tx);
|
|
279
318
|
self
|
|
280
319
|
}
|
|
281
320
|
|
|
@@ -537,7 +576,7 @@ pub fn get_integ_telem_options() -> TelemetryOptions {
|
|
|
537
576
|
|
|
538
577
|
pub fn default_cached_download() -> EphemeralExe {
|
|
539
578
|
EphemeralExe::CachedDownload {
|
|
540
|
-
version: EphemeralExeVersion::
|
|
579
|
+
version: EphemeralExeVersion::SDKDefault {
|
|
541
580
|
sdk_name: "sdk-rust".to_string(),
|
|
542
581
|
sdk_version: "0.1.0".to_string(),
|
|
543
582
|
},
|
|
@@ -556,7 +595,7 @@ pub fn schedule_activity_cmd(
|
|
|
556
595
|
ScheduleActivity {
|
|
557
596
|
seq,
|
|
558
597
|
activity_id: activity_id.to_string(),
|
|
559
|
-
activity_type:
|
|
598
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
560
599
|
task_queue: task_q.to_owned(),
|
|
561
600
|
schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
562
601
|
start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
@@ -577,7 +616,7 @@ pub fn schedule_local_activity_cmd(
|
|
|
577
616
|
ScheduleLocalActivity {
|
|
578
617
|
seq,
|
|
579
618
|
activity_id: activity_id.to_string(),
|
|
580
|
-
activity_type:
|
|
619
|
+
activity_type: DEFAULT_ACTIVITY_TYPE.to_string(),
|
|
581
620
|
schedule_to_start_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
582
621
|
start_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
583
622
|
schedule_to_close_timeout: Some(activity_timeout.try_into().expect("duration fits")),
|
|
@@ -648,3 +687,23 @@ where
|
|
|
648
687
|
.unwrap();
|
|
649
688
|
}
|
|
650
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
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
use anyhow::anyhow;
|
|
2
|
+
use bytes::BytesMut;
|
|
3
|
+
use futures::{stream::BoxStream, SinkExt, StreamExt};
|
|
4
|
+
use prost::bytes::Bytes;
|
|
5
|
+
use std::path::Path;
|
|
6
|
+
use temporal_sdk_core_api::worker::WorkerConfig;
|
|
7
|
+
use tokio::{fs::File, sync::mpsc::UnboundedReceiver};
|
|
8
|
+
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
|
|
9
|
+
|
|
10
|
+
pub struct WFStateReplayData {
|
|
11
|
+
pub config: WorkerConfig,
|
|
12
|
+
pub inputs: BoxStream<'static, Result<BytesMut, std::io::Error>>,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub async fn stream_to_file(
|
|
16
|
+
config: &WorkerConfig,
|
|
17
|
+
mut rcv: UnboundedReceiver<Vec<u8>>,
|
|
18
|
+
) -> Result<(), anyhow::Error> {
|
|
19
|
+
let file = File::create("wf_inputs").await?;
|
|
20
|
+
let mut transport = FramedWrite::new(file, ldc());
|
|
21
|
+
// First write the worker config, since things like cache size affect how many evictions there
|
|
22
|
+
// will be, etc.
|
|
23
|
+
transport.send(rmp_serde::to_vec(config)?.into()).await?;
|
|
24
|
+
while let Some(v) = rcv.recv().await {
|
|
25
|
+
transport.send(Bytes::from(v)).await?;
|
|
26
|
+
}
|
|
27
|
+
Ok(())
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub async fn read_from_file(path: impl AsRef<Path>) -> Result<WFStateReplayData, anyhow::Error> {
|
|
31
|
+
let file = File::open(path).await?;
|
|
32
|
+
let mut framed_read = FramedRead::new(file, ldc());
|
|
33
|
+
// Deserialize the worker config first
|
|
34
|
+
let config = framed_read
|
|
35
|
+
.next()
|
|
36
|
+
.await
|
|
37
|
+
.ok_or_else(|| anyhow!("Replay data file is empty"))??;
|
|
38
|
+
let config = rmp_serde::from_slice(config.as_ref())?;
|
|
39
|
+
|
|
40
|
+
Ok(WFStateReplayData {
|
|
41
|
+
config,
|
|
42
|
+
inputs: framed_read.boxed(),
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fn ldc() -> LengthDelimitedCodec {
|
|
47
|
+
LengthDelimitedCodec::builder()
|
|
48
|
+
.length_field_type::<u16>()
|
|
49
|
+
.new_codec()
|
|
50
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
use crate::prost_dur;
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
use temporal_sdk::{ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
|
|
4
|
+
use temporal_sdk_core_protos::{coresdk::AsJsonPayloadExt, temporal::api::common::v1::RetryPolicy};
|
|
5
|
+
|
|
6
|
+
pub async fn la_problem_workflow(ctx: WfContext) -> WorkflowResult<()> {
|
|
7
|
+
ctx.local_activity(LocalActivityOptions {
|
|
8
|
+
activity_type: "delay".to_string(),
|
|
9
|
+
input: "hi".as_json_payload().expect("serializes fine"),
|
|
10
|
+
retry_policy: RetryPolicy {
|
|
11
|
+
initial_interval: Some(prost_dur!(from_micros(15))),
|
|
12
|
+
backoff_coefficient: 1_000.,
|
|
13
|
+
maximum_interval: Some(prost_dur!(from_millis(1500))),
|
|
14
|
+
maximum_attempts: 4,
|
|
15
|
+
non_retryable_error_types: vec![],
|
|
16
|
+
},
|
|
17
|
+
timer_backoff_threshold: Some(Duration::from_secs(1)),
|
|
18
|
+
..Default::default()
|
|
19
|
+
})
|
|
20
|
+
.await;
|
|
21
|
+
ctx.activity(ActivityOptions {
|
|
22
|
+
activity_type: "delay".to_string(),
|
|
23
|
+
start_to_close_timeout: Some(Duration::from_secs(20)),
|
|
24
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
25
|
+
..Default::default()
|
|
26
|
+
})
|
|
27
|
+
.await;
|
|
28
|
+
Ok(().into())
|
|
29
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
use futures_util::{sink, stream::FuturesUnordered, FutureExt, StreamExt};
|
|
2
|
+
use rand::{prelude::Distribution, rngs::SmallRng, Rng, SeedableRng};
|
|
3
|
+
use std::{future, time::Duration};
|
|
4
|
+
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowOptions};
|
|
5
|
+
use temporal_sdk::{ActContext, ActivityOptions, LocalActivityOptions, WfContext, WorkflowResult};
|
|
6
|
+
use temporal_sdk_core_protos::coresdk::{AsJsonPayloadExt, FromJsonPayloadExt, IntoPayloadsExt};
|
|
7
|
+
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
8
|
+
use tokio_util::sync::CancellationToken;
|
|
9
|
+
|
|
10
|
+
const FUZZY_SIG: &str = "fuzzy_sig";
|
|
11
|
+
|
|
12
|
+
#[derive(serde::Serialize, serde::Deserialize, Copy, Clone)]
|
|
13
|
+
enum FuzzyWfAction {
|
|
14
|
+
Shutdown,
|
|
15
|
+
DoAct,
|
|
16
|
+
DoLocalAct,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
struct FuzzyWfActionSampler;
|
|
20
|
+
impl Distribution<FuzzyWfAction> for FuzzyWfActionSampler {
|
|
21
|
+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> FuzzyWfAction {
|
|
22
|
+
let v: u8 = rng.gen_range(1..=2);
|
|
23
|
+
match v {
|
|
24
|
+
1 => FuzzyWfAction::DoAct,
|
|
25
|
+
2 => FuzzyWfAction::DoLocalAct,
|
|
26
|
+
_ => unreachable!(),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async fn echo(_ctx: ActContext, echo_me: String) -> Result<String, anyhow::Error> {
|
|
32
|
+
Ok(echo_me)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async fn fuzzy_wf_def(ctx: WfContext) -> WorkflowResult<()> {
|
|
36
|
+
let sigchan = ctx
|
|
37
|
+
.make_signal_channel(FUZZY_SIG)
|
|
38
|
+
.map(|sd| FuzzyWfAction::from_json_payload(&sd.input[0]).expect("Can deserialize signal"));
|
|
39
|
+
let done = CancellationToken::new();
|
|
40
|
+
let done_setter = done.clone();
|
|
41
|
+
|
|
42
|
+
sigchan
|
|
43
|
+
.take_until(done.cancelled())
|
|
44
|
+
.for_each_concurrent(None, |action| {
|
|
45
|
+
let fut = match action {
|
|
46
|
+
FuzzyWfAction::DoAct => ctx
|
|
47
|
+
.activity(ActivityOptions {
|
|
48
|
+
activity_type: "echo_activity".to_string(),
|
|
49
|
+
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
50
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
51
|
+
..Default::default()
|
|
52
|
+
})
|
|
53
|
+
.map(|_| ())
|
|
54
|
+
.boxed(),
|
|
55
|
+
FuzzyWfAction::DoLocalAct => ctx
|
|
56
|
+
.local_activity(LocalActivityOptions {
|
|
57
|
+
activity_type: "echo_activity".to_string(),
|
|
58
|
+
start_to_close_timeout: Some(Duration::from_secs(5)),
|
|
59
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
60
|
+
..Default::default()
|
|
61
|
+
})
|
|
62
|
+
.map(|_| ())
|
|
63
|
+
.boxed(),
|
|
64
|
+
FuzzyWfAction::Shutdown => {
|
|
65
|
+
done_setter.cancel();
|
|
66
|
+
future::ready(()).boxed()
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
fut
|
|
70
|
+
})
|
|
71
|
+
.await;
|
|
72
|
+
|
|
73
|
+
Ok(().into())
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
|
77
|
+
async fn fuzzy_workflow() {
|
|
78
|
+
let num_workflows = 200;
|
|
79
|
+
let wf_name = "fuzzy_wf";
|
|
80
|
+
let mut starter = CoreWfStarter::new("fuzzy_workflow");
|
|
81
|
+
starter.max_wft(25).max_cached_workflows(25).max_at(25);
|
|
82
|
+
// .enable_wf_state_input_recording();
|
|
83
|
+
let mut worker = starter.worker().await;
|
|
84
|
+
worker.register_wf(wf_name.to_owned(), fuzzy_wf_def);
|
|
85
|
+
worker.register_activity("echo_activity", echo);
|
|
86
|
+
let client = starter.get_client().await;
|
|
87
|
+
|
|
88
|
+
let mut workflow_handles = vec![];
|
|
89
|
+
for i in 0..num_workflows {
|
|
90
|
+
let wfid = format!("{wf_name}_{i}");
|
|
91
|
+
let rid = worker
|
|
92
|
+
.submit_wf(
|
|
93
|
+
wfid.clone(),
|
|
94
|
+
wf_name.to_owned(),
|
|
95
|
+
vec![],
|
|
96
|
+
WorkflowOptions::default(),
|
|
97
|
+
)
|
|
98
|
+
.await
|
|
99
|
+
.unwrap();
|
|
100
|
+
workflow_handles.push(client.get_untyped_workflow_handle(wfid, rid));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let rng = SmallRng::seed_from_u64(523189);
|
|
104
|
+
let mut actions: Vec<FuzzyWfAction> = rng.sample_iter(FuzzyWfActionSampler).take(15).collect();
|
|
105
|
+
actions.push(FuzzyWfAction::Shutdown);
|
|
106
|
+
|
|
107
|
+
let sig_sender = async {
|
|
108
|
+
for action in actions {
|
|
109
|
+
let sends: FuturesUnordered<_> = (0..num_workflows)
|
|
110
|
+
.map(|i| {
|
|
111
|
+
client.signal_workflow_execution(
|
|
112
|
+
format!("{wf_name}_{i}"),
|
|
113
|
+
"".to_string(),
|
|
114
|
+
FUZZY_SIG.to_string(),
|
|
115
|
+
[action.as_json_payload().expect("Serializes ok")].into_payloads(),
|
|
116
|
+
None,
|
|
117
|
+
)
|
|
118
|
+
})
|
|
119
|
+
.collect();
|
|
120
|
+
sends
|
|
121
|
+
.map(|_| Ok(()))
|
|
122
|
+
.forward(sink::drain())
|
|
123
|
+
.await
|
|
124
|
+
.expect("Sending signals works");
|
|
125
|
+
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
let (r1, _) = tokio::join!(worker.run_until_done(), sig_sender);
|
|
129
|
+
r1.unwrap();
|
|
130
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
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
|
-
use temporal_sdk::{ActContext, ActivityOptions, WfContext};
|
|
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
|
-
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
8
|
+
use temporal_sdk_core_test_utils::{workflows::la_problem_workflow, CoreWfStarter};
|
|
9
|
+
|
|
10
|
+
mod fuzzy_workflow;
|
|
11
11
|
|
|
12
12
|
#[tokio::test]
|
|
13
13
|
async fn activity_load() {
|
|
14
|
-
const CONCURRENCY: usize =
|
|
14
|
+
const CONCURRENCY: usize = 512;
|
|
15
15
|
|
|
16
16
|
let mut starter = CoreWfStarter::new("activity_load");
|
|
17
17
|
starter
|
|
@@ -23,18 +23,16 @@ async fn activity_load() {
|
|
|
23
23
|
|
|
24
24
|
let activity_id = "act-1";
|
|
25
25
|
let activity_timeout = Duration::from_secs(8);
|
|
26
|
-
let payload_dat = b"hello".to_vec();
|
|
27
26
|
let task_queue = starter.get_task_queue().to_owned();
|
|
28
27
|
|
|
29
|
-
let pd = payload_dat.clone();
|
|
30
28
|
let wf_fn = move |ctx: WfContext| {
|
|
31
29
|
let task_queue = task_queue.clone();
|
|
32
|
-
let
|
|
33
|
-
|
|
30
|
+
let payload = "yo".as_json_payload().unwrap();
|
|
34
31
|
async move {
|
|
35
32
|
let activity = ActivityOptions {
|
|
36
33
|
activity_id: Some(activity_id.to_string()),
|
|
37
34
|
activity_type: "test_activity".to_string(),
|
|
35
|
+
input: payload.clone(),
|
|
38
36
|
task_queue,
|
|
39
37
|
schedule_to_start_timeout: Some(activity_timeout),
|
|
40
38
|
start_to_close_timeout: Some(activity_timeout),
|
|
@@ -44,7 +42,7 @@ async fn activity_load() {
|
|
|
44
42
|
..Default::default()
|
|
45
43
|
};
|
|
46
44
|
let res = ctx.activity(activity).await.unwrap_ok_payload();
|
|
47
|
-
assert_eq!(res.data,
|
|
45
|
+
assert_eq!(res.data, payload.data);
|
|
48
46
|
Ok(().into())
|
|
49
47
|
}
|
|
50
48
|
};
|
|
@@ -52,9 +50,13 @@ async fn activity_load() {
|
|
|
52
50
|
let starting = Instant::now();
|
|
53
51
|
let wf_type = "activity_load";
|
|
54
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
|
+
);
|
|
55
57
|
join_all((0..CONCURRENCY).map(|i| {
|
|
56
58
|
let worker = &worker;
|
|
57
|
-
let wf_id = format!("activity_load_{}"
|
|
59
|
+
let wf_id = format!("activity_load_{i}");
|
|
58
60
|
async move {
|
|
59
61
|
worker
|
|
60
62
|
.submit_wf(
|
|
@@ -71,42 +73,8 @@ async fn activity_load() {
|
|
|
71
73
|
dbg!(starting.elapsed());
|
|
72
74
|
|
|
73
75
|
let running = Instant::now();
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Poll for and complete all activities
|
|
77
|
-
let c2 = core.clone();
|
|
78
|
-
let all_acts = async move {
|
|
79
|
-
let mut act_complete_futs = vec![];
|
|
80
|
-
for _ in 0..CONCURRENCY {
|
|
81
|
-
let task = c2.poll_activity_task().await.unwrap();
|
|
82
|
-
assert_matches!(
|
|
83
|
-
task.variant,
|
|
84
|
-
Some(act_task::Variant::Start(ref start_activity)) => {
|
|
85
|
-
assert_eq!(start_activity.activity_type, "test_activity")
|
|
86
|
-
}
|
|
87
|
-
);
|
|
88
|
-
let pd = payload_dat.clone();
|
|
89
|
-
let core = c2.clone();
|
|
90
|
-
act_complete_futs.push(tokio::spawn(async move {
|
|
91
|
-
core.complete_activity_task(ActivityTaskCompletion {
|
|
92
|
-
task_token: task.task_token,
|
|
93
|
-
result: Some(ActivityExecutionResult::ok(pd.into())),
|
|
94
|
-
})
|
|
95
|
-
.await
|
|
96
|
-
.unwrap()
|
|
97
|
-
}));
|
|
98
|
-
}
|
|
99
|
-
join_all(act_complete_futs)
|
|
100
|
-
.await
|
|
101
|
-
.into_iter()
|
|
102
|
-
.for_each(|h| h.unwrap());
|
|
103
|
-
};
|
|
104
|
-
tokio::join! {
|
|
105
|
-
async {
|
|
106
|
-
worker.run_until_done().await.unwrap();
|
|
107
|
-
},
|
|
108
|
-
all_acts
|
|
109
|
-
};
|
|
76
|
+
|
|
77
|
+
worker.run_until_done().await.unwrap();
|
|
110
78
|
dbg!(running.elapsed());
|
|
111
79
|
}
|
|
112
80
|
|
|
@@ -153,7 +121,7 @@ async fn workflow_load() {
|
|
|
153
121
|
|
|
154
122
|
let mut workflow_handles = vec![];
|
|
155
123
|
for i in 0..num_workflows {
|
|
156
|
-
let wfid = format!("{}_{}"
|
|
124
|
+
let wfid = format!("{wf_name}_{i}");
|
|
157
125
|
let rid = worker
|
|
158
126
|
.submit_wf(
|
|
159
127
|
wfid.clone(),
|
|
@@ -171,7 +139,7 @@ async fn workflow_load() {
|
|
|
171
139
|
let sends: FuturesUnordered<_> = (0..num_workflows)
|
|
172
140
|
.map(|i| {
|
|
173
141
|
client.signal_workflow_execution(
|
|
174
|
-
format!("{}_{}"
|
|
142
|
+
format!("{wf_name}_{i}"),
|
|
175
143
|
"".to_string(),
|
|
176
144
|
SIGNAME.to_string(),
|
|
177
145
|
None,
|
|
@@ -187,5 +155,111 @@ async fn workflow_load() {
|
|
|
187
155
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
188
156
|
}
|
|
189
157
|
};
|
|
190
|
-
tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}}
|
|
158
|
+
tokio::select! { r1 = worker.run_until_done() => {r1.unwrap()}, _ = sig_sender => {}}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
|
162
|
+
async fn evict_while_la_running_no_interference() {
|
|
163
|
+
let wf_name = "evict_while_la_running_no_interference";
|
|
164
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
165
|
+
starter.max_local_at(20);
|
|
166
|
+
starter.max_cached_workflows(20);
|
|
167
|
+
// Though it doesn't make sense to set wft higher than cached workflows, leaving this commented
|
|
168
|
+
// introduces more instability that can be useful in the test.
|
|
169
|
+
// starter.max_wft(20);
|
|
170
|
+
let mut worker = starter.worker().await;
|
|
171
|
+
|
|
172
|
+
worker.register_wf(wf_name.to_owned(), la_problem_workflow);
|
|
173
|
+
worker.register_activity("delay", |_: ActContext, _: String| async {
|
|
174
|
+
tokio::time::sleep(Duration::from_secs(15)).await;
|
|
175
|
+
Ok(())
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
let client = starter.get_client().await;
|
|
179
|
+
let subfs = FuturesUnordered::new();
|
|
180
|
+
for i in 1..100 {
|
|
181
|
+
let wf_id = format!("{wf_name}-{i}");
|
|
182
|
+
let run_id = worker
|
|
183
|
+
.submit_wf(
|
|
184
|
+
&wf_id,
|
|
185
|
+
wf_name.to_owned(),
|
|
186
|
+
vec![],
|
|
187
|
+
WorkflowOptions::default(),
|
|
188
|
+
)
|
|
189
|
+
.await
|
|
190
|
+
.unwrap();
|
|
191
|
+
let cw = worker.core_worker.clone();
|
|
192
|
+
let client = client.clone();
|
|
193
|
+
subfs.push(async move {
|
|
194
|
+
// Evict the workflow
|
|
195
|
+
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
196
|
+
cw.request_workflow_eviction(&run_id);
|
|
197
|
+
// Wake up workflow by sending signal
|
|
198
|
+
client
|
|
199
|
+
.signal_workflow_execution(
|
|
200
|
+
wf_id,
|
|
201
|
+
run_id.clone(),
|
|
202
|
+
"whaatever".to_string(),
|
|
203
|
+
None,
|
|
204
|
+
None,
|
|
205
|
+
)
|
|
206
|
+
.await
|
|
207
|
+
.unwrap();
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
let runf = async {
|
|
211
|
+
worker.run_until_done().await.unwrap();
|
|
212
|
+
};
|
|
213
|
+
tokio::join!(subfs.collect::<Vec<_>>(), runf);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
pub async fn many_parallel_timers_longhist(ctx: WfContext) -> WorkflowResult<()> {
|
|
217
|
+
for _ in 0..120 {
|
|
218
|
+
let mut futs = vec![];
|
|
219
|
+
for _ in 0..100 {
|
|
220
|
+
futs.push(ctx.timer(Duration::from_millis(100)));
|
|
221
|
+
}
|
|
222
|
+
join_all(futs).await;
|
|
223
|
+
}
|
|
224
|
+
Ok(().into())
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
#[tokio::test]
|
|
228
|
+
async fn can_paginate_long_history() {
|
|
229
|
+
let wf_name = "can_paginate_long_history";
|
|
230
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
231
|
+
starter.no_remote_activities();
|
|
232
|
+
// Do not use sticky queues so we are forced to paginate once history gets long
|
|
233
|
+
starter.max_cached_workflows(0);
|
|
234
|
+
|
|
235
|
+
let mut worker = starter.worker().await;
|
|
236
|
+
worker.register_wf(wf_name.to_owned(), many_parallel_timers_longhist);
|
|
237
|
+
let run_id = worker
|
|
238
|
+
.submit_wf(
|
|
239
|
+
wf_name.to_owned(),
|
|
240
|
+
wf_name.to_owned(),
|
|
241
|
+
vec![],
|
|
242
|
+
WorkflowOptions::default(),
|
|
243
|
+
)
|
|
244
|
+
.await
|
|
245
|
+
.unwrap();
|
|
246
|
+
let client = starter.get_client().await;
|
|
247
|
+
tokio::spawn(async move {
|
|
248
|
+
loop {
|
|
249
|
+
for _ in 0..10 {
|
|
250
|
+
client
|
|
251
|
+
.signal_workflow_execution(
|
|
252
|
+
wf_name.to_owned(),
|
|
253
|
+
run_id.clone(),
|
|
254
|
+
"sig".to_string(),
|
|
255
|
+
None,
|
|
256
|
+
None,
|
|
257
|
+
)
|
|
258
|
+
.await
|
|
259
|
+
.unwrap();
|
|
260
|
+
}
|
|
261
|
+
tokio::time::sleep(Duration::from_secs(3)).await;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
worker.run_until_done().await.unwrap();
|
|
191
265
|
}
|