@temporalio/core-bridge 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +255 -48
- package/package.json +4 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/pipeline.yml +1 -3
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +28 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +9 -5
- package/sdk-core/client/src/lib.rs +211 -36
- package/sdk-core/client/src/raw.rs +1 -1
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +23 -9
- package/sdk-core/core/src/abstractions.rs +11 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +6 -5
- package/sdk-core/core/src/core_tests/local_activities.rs +263 -22
- package/sdk-core/core/src/core_tests/queries.rs +2 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +249 -5
- package/sdk-core/core/src/ephemeral_server/mod.rs +5 -6
- package/sdk-core/core/src/lib.rs +2 -0
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/mod.rs +23 -8
- package/sdk-core/core/src/test_help/mod.rs +8 -1
- package/sdk-core/core/src/worker/activities/local_activities.rs +259 -125
- package/sdk-core/core/src/worker/activities.rs +3 -2
- package/sdk-core/core/src/worker/mod.rs +53 -26
- package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- package/sdk-core/core/src/worker/workflow/history_update.rs +835 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +9 -17
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +73 -51
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -3
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +3 -5
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +89 -58
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +4 -7
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +21 -9
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1021 -360
- package/sdk-core/core/src/worker/workflow/mod.rs +306 -346
- package/sdk-core/core/src/worker/workflow/run_cache.rs +29 -53
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +115 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +444 -714
- package/sdk-core/core-api/Cargo.toml +2 -0
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +6 -2
- package/sdk-core/core-api/src/worker.rs +14 -1
- package/sdk-core/etc/deps.svg +115 -140
- package/sdk-core/etc/regen-depgraph.sh +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -6
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -3
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- package/sdk-core/protos/api_upstream/Makefile +5 -5
- package/sdk-core/protos/api_upstream/build/go.mod +7 -0
- package/sdk-core/protos/api_upstream/build/go.sum +5 -0
- package/sdk-core/protos/api_upstream/build/tools.go +29 -0
- package/sdk-core/protos/api_upstream/go.mod +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +12 -19
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +3 -3
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -2
- package/sdk-core/protos/api_upstream/temporal/api/{update/v1/message.proto → enums/v1/interaction_type.proto} +11 -18
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +2 -13
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -19
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +87 -0
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +13 -8
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- package/sdk-core/sdk/Cargo.toml +4 -3
- package/sdk-core/sdk/src/lib.rs +87 -21
- package/sdk-core/sdk/src/workflow_future.rs +7 -12
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- package/sdk-core/sdk-core-protos/build.rs +36 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +26 -19
- package/sdk-core/sdk-core-protos/src/history_info.rs +4 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +78 -34
- package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +50 -18
- package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- package/sdk-core/test-utils/src/workflows.rs +29 -0
- package/sdk-core/tests/fuzzy_workflow.rs +130 -0
- package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +114 -7
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -2
- package/sdk-core/tests/integ_tests/metrics_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -39
- package/sdk-core/tests/integ_tests/queries_tests.rs +2 -127
- package/sdk-core/tests/integ_tests/visibility_tests.rs +52 -5
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +74 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +5 -13
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +2 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +69 -197
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +4 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -19
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +5 -6
- package/sdk-core/tests/main.rs +2 -12
- package/sdk-core/tests/runner.rs +71 -34
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/sdk-core/bridge-ffi/Cargo.toml +0 -24
- package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- package/sdk-core/bridge-ffi/build.rs +0 -25
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
- package/sdk-core/bridge-ffi/src/lib.rs +0 -746
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- package/sdk-core/sdk/src/conversions.rs +0 -8
|
@@ -67,7 +67,7 @@ pub mod coresdk {
|
|
|
67
67
|
fmt_tt(&self.task_token),
|
|
68
68
|
)?;
|
|
69
69
|
if let Some(r) = self.result.as_ref().and_then(|r| r.status.as_ref()) {
|
|
70
|
-
write!(f, ", {}"
|
|
70
|
+
write!(f, ", {r}")?;
|
|
71
71
|
} else {
|
|
72
72
|
write!(f, ", missing result")?;
|
|
73
73
|
}
|
|
@@ -125,13 +125,13 @@ pub mod coresdk {
|
|
|
125
125
|
write!(f, "ActivityExecutionResult(")?;
|
|
126
126
|
match self {
|
|
127
127
|
aer::Status::Completed(v) => {
|
|
128
|
-
write!(f, "{})"
|
|
128
|
+
write!(f, "{v})")
|
|
129
129
|
}
|
|
130
130
|
aer::Status::Failed(v) => {
|
|
131
|
-
write!(f, "{})"
|
|
131
|
+
write!(f, "{v})")
|
|
132
132
|
}
|
|
133
133
|
aer::Status::Cancelled(v) => {
|
|
134
|
-
write!(f, "{})"
|
|
134
|
+
write!(f, "{v})")
|
|
135
135
|
}
|
|
136
136
|
aer::Status::WillCompleteAsync(_) => {
|
|
137
137
|
write!(f, "Will complete async)")
|
|
@@ -144,7 +144,7 @@ pub mod coresdk {
|
|
|
144
144
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
145
145
|
write!(f, "Success(")?;
|
|
146
146
|
if let Some(ref v) = self.result {
|
|
147
|
-
write!(f, "{}"
|
|
147
|
+
write!(f, "{v}")?;
|
|
148
148
|
}
|
|
149
149
|
write!(f, ")")
|
|
150
150
|
}
|
|
@@ -154,7 +154,7 @@ pub mod coresdk {
|
|
|
154
154
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
155
155
|
write!(f, "Failure(")?;
|
|
156
156
|
if let Some(ref v) = self.failure {
|
|
157
|
-
write!(f, "{}"
|
|
157
|
+
write!(f, "{v}")?;
|
|
158
158
|
}
|
|
159
159
|
write!(f, ")")
|
|
160
160
|
}
|
|
@@ -164,7 +164,7 @@ pub mod coresdk {
|
|
|
164
164
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
165
165
|
write!(f, "Cancellation(")?;
|
|
166
166
|
if let Some(ref v) = self.failure {
|
|
167
|
-
write!(f, "{}"
|
|
167
|
+
write!(f, "{v}")?;
|
|
168
168
|
}
|
|
169
169
|
write!(f, ")")
|
|
170
170
|
}
|
|
@@ -197,11 +197,15 @@ pub mod coresdk {
|
|
|
197
197
|
matches!(self.status, Some(activity_resolution::Status::Failed(_)))
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
pub fn timed_out(&self) ->
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
pub fn timed_out(&self) -> Option<crate::temporal::api::enums::v1::TimeoutType> {
|
|
201
|
+
match self.status {
|
|
202
|
+
Some(activity_resolution::Status::Failed(Failure {
|
|
203
|
+
failure: Some(ref f),
|
|
204
|
+
})) => f
|
|
205
|
+
.is_timeout()
|
|
206
|
+
.or_else(|| f.cause.as_ref().and_then(|c| c.is_timeout())),
|
|
207
|
+
_ => None,
|
|
208
|
+
}
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
pub fn cancelled(&self) -> bool {
|
|
@@ -243,10 +247,6 @@ pub mod coresdk {
|
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
246
|
-
pub mod bridge {
|
|
247
|
-
tonic::include_proto!("coresdk.bridge");
|
|
248
|
-
}
|
|
249
|
-
|
|
250
250
|
pub mod common {
|
|
251
251
|
tonic::include_proto!("coresdk.common");
|
|
252
252
|
use super::external_data::LocalActivityMarkerData;
|
|
@@ -317,7 +317,7 @@ pub mod coresdk {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
pub mod external_data {
|
|
320
|
-
use
|
|
320
|
+
use prost_wkt_types::{Duration, Timestamp};
|
|
321
321
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
322
322
|
tonic::include_proto!("coresdk.external_data");
|
|
323
323
|
|
|
@@ -404,7 +404,7 @@ pub mod coresdk {
|
|
|
404
404
|
query::v1::WorkflowQuery,
|
|
405
405
|
},
|
|
406
406
|
};
|
|
407
|
-
use
|
|
407
|
+
use prost_wkt_types::Timestamp;
|
|
408
408
|
use std::{
|
|
409
409
|
collections::HashMap,
|
|
410
410
|
fmt::{Display, Formatter},
|
|
@@ -491,7 +491,7 @@ pub mod coresdk {
|
|
|
491
491
|
|
|
492
492
|
impl Display for EvictionReason {
|
|
493
493
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
494
|
-
write!(f, "{:?}"
|
|
494
|
+
write!(f, "{self:?}")
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
|
|
@@ -517,7 +517,7 @@ pub mod coresdk {
|
|
|
517
517
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
518
518
|
match &self.variant {
|
|
519
519
|
None => write!(f, "empty"),
|
|
520
|
-
Some(v) => write!(f, "{}"
|
|
520
|
+
Some(v) => write!(f, "{v}"),
|
|
521
521
|
}
|
|
522
522
|
}
|
|
523
523
|
}
|
|
@@ -673,7 +673,7 @@ pub mod coresdk {
|
|
|
673
673
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
674
674
|
match &self.variant {
|
|
675
675
|
None => write!(f, "Empty"),
|
|
676
|
-
Some(v) => write!(f, "{}"
|
|
676
|
+
Some(v) => write!(f, "{v}"),
|
|
677
677
|
}
|
|
678
678
|
}
|
|
679
679
|
}
|
|
@@ -1027,7 +1027,7 @@ pub mod coresdk {
|
|
|
1027
1027
|
)?;
|
|
1028
1028
|
match &self.status {
|
|
1029
1029
|
None => write!(f, "empty")?,
|
|
1030
|
-
Some(s) => write!(f, "{}"
|
|
1030
|
+
Some(s) => write!(f, "{s}")?,
|
|
1031
1031
|
};
|
|
1032
1032
|
write!(f, ")")
|
|
1033
1033
|
}
|
|
@@ -1042,7 +1042,7 @@ pub mod coresdk {
|
|
|
1042
1042
|
write!(f, "Success(")?;
|
|
1043
1043
|
let mut written = 0;
|
|
1044
1044
|
for c in commands {
|
|
1045
|
-
write!(f, "{} "
|
|
1045
|
+
write!(f, "{c} ")?;
|
|
1046
1046
|
written += 1;
|
|
1047
1047
|
if written >= 10 && written < commands.len() {
|
|
1048
1048
|
write!(f, "... {} more", commands.len() - written)?;
|
|
@@ -1107,8 +1107,11 @@ pub mod coresdk {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
1109
|
impl Failure {
|
|
1110
|
-
pub fn is_timeout(&self) ->
|
|
1111
|
-
|
|
1110
|
+
pub fn is_timeout(&self) -> Option<crate::temporal::api::enums::v1::TimeoutType> {
|
|
1111
|
+
match &self.failure_info {
|
|
1112
|
+
Some(FailureInfo::TimeoutFailureInfo(ti)) => Some(ti.timeout_type()),
|
|
1113
|
+
_ => None,
|
|
1114
|
+
}
|
|
1112
1115
|
}
|
|
1113
1116
|
|
|
1114
1117
|
pub fn application_failure(message: String, non_retryable: bool) -> Self {
|
|
@@ -1124,6 +1127,26 @@ pub mod coresdk {
|
|
|
1124
1127
|
}
|
|
1125
1128
|
}
|
|
1126
1129
|
|
|
1130
|
+
pub fn application_failure_from_error(ae: anyhow::Error, non_retryable: bool) -> Self {
|
|
1131
|
+
Self {
|
|
1132
|
+
failure_info: Some(FailureInfo::ApplicationFailureInfo(
|
|
1133
|
+
ApplicationFailureInfo {
|
|
1134
|
+
non_retryable,
|
|
1135
|
+
..Default::default()
|
|
1136
|
+
},
|
|
1137
|
+
)),
|
|
1138
|
+
..ae.chain()
|
|
1139
|
+
.rfold(None, |cause, e| {
|
|
1140
|
+
Some(Self {
|
|
1141
|
+
message: e.to_string(),
|
|
1142
|
+
cause: cause.map(Box::new),
|
|
1143
|
+
..Default::default()
|
|
1144
|
+
})
|
|
1145
|
+
})
|
|
1146
|
+
.unwrap_or_default()
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1127
1150
|
/// Extracts an ApplicationFailureInfo from a Failure instance if it exists
|
|
1128
1151
|
pub fn maybe_application_failure(&self) -> Option<&ApplicationFailureInfo> {
|
|
1129
1152
|
if let Failure {
|
|
@@ -1194,7 +1217,7 @@ pub mod coresdk {
|
|
|
1194
1217
|
|
|
1195
1218
|
impl From<anyhow::Error> for Failure {
|
|
1196
1219
|
fn from(ae: anyhow::Error) -> Self {
|
|
1197
|
-
Failure::
|
|
1220
|
+
Failure::application_failure_from_error(ae, false)
|
|
1198
1221
|
}
|
|
1199
1222
|
}
|
|
1200
1223
|
|
|
@@ -1550,6 +1573,7 @@ pub mod temporal {
|
|
|
1550
1573
|
}
|
|
1551
1574
|
pub mod common {
|
|
1552
1575
|
pub mod v1 {
|
|
1576
|
+
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
1553
1577
|
use std::{
|
|
1554
1578
|
collections::HashMap,
|
|
1555
1579
|
fmt::{Display, Formatter},
|
|
@@ -1586,11 +1610,11 @@ pub mod temporal {
|
|
|
1586
1610
|
write!(
|
|
1587
1611
|
f,
|
|
1588
1612
|
"[{}..{}]",
|
|
1589
|
-
|
|
1590
|
-
|
|
1613
|
+
BASE64_STANDARD.encode(windows.next().unwrap_or_default()),
|
|
1614
|
+
BASE64_STANDARD.encode(windows.next_back().unwrap_or_default())
|
|
1591
1615
|
)
|
|
1592
1616
|
} else {
|
|
1593
|
-
write!(f, "[{}]",
|
|
1617
|
+
write!(f, "[{}]", BASE64_STANDARD.encode(&self.data))
|
|
1594
1618
|
}
|
|
1595
1619
|
}
|
|
1596
1620
|
}
|
|
@@ -1771,6 +1795,11 @@ pub mod temporal {
|
|
|
1771
1795
|
}
|
|
1772
1796
|
}
|
|
1773
1797
|
}
|
|
1798
|
+
pub mod interaction {
|
|
1799
|
+
pub mod v1 {
|
|
1800
|
+
tonic::include_proto!("temporal.api.interaction.v1");
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1774
1803
|
pub mod namespace {
|
|
1775
1804
|
pub mod v1 {
|
|
1776
1805
|
tonic::include_proto!("temporal.api.namespace.v1");
|
|
@@ -1816,11 +1845,6 @@ pub mod temporal {
|
|
|
1816
1845
|
tonic::include_proto!("temporal.api.testservice.v1");
|
|
1817
1846
|
}
|
|
1818
1847
|
}
|
|
1819
|
-
pub mod update {
|
|
1820
|
-
pub mod v1 {
|
|
1821
|
-
tonic::include_proto!("temporal.api.update.v1");
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
1848
|
pub mod version {
|
|
1825
1849
|
pub mod v1 {
|
|
1826
1850
|
tonic::include_proto!("temporal.api.version.v1");
|
|
@@ -1930,3 +1954,23 @@ pub mod grpc {
|
|
|
1930
1954
|
}
|
|
1931
1955
|
}
|
|
1932
1956
|
}
|
|
1957
|
+
|
|
1958
|
+
#[cfg(test)]
|
|
1959
|
+
mod tests {
|
|
1960
|
+
use crate::temporal::api::failure::v1::Failure;
|
|
1961
|
+
use anyhow::anyhow;
|
|
1962
|
+
|
|
1963
|
+
#[test]
|
|
1964
|
+
fn anyhow_to_failure_conversion() {
|
|
1965
|
+
let no_causes: Failure = anyhow!("no causes").into();
|
|
1966
|
+
assert_eq!(no_causes.cause, None);
|
|
1967
|
+
assert_eq!(no_causes.message, "no causes");
|
|
1968
|
+
let orig = anyhow!("fail 1");
|
|
1969
|
+
let mid = orig.context("fail 2");
|
|
1970
|
+
let top = mid.context("fail 3");
|
|
1971
|
+
let as_fail: Failure = top.into();
|
|
1972
|
+
assert_eq!(as_fail.message, "fail 3");
|
|
1973
|
+
assert_eq!(as_fail.cause.as_ref().unwrap().message, "fail 2");
|
|
1974
|
+
assert_eq!(as_fail.cause.unwrap().cause.unwrap().message, "fail 1");
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
1
2
|
use std::fmt::{Debug, Display, Formatter};
|
|
2
3
|
|
|
3
4
|
static LOCAL_ACT_TASK_TOKEN_PREFIX: &[u8] = b"local_act_";
|
|
4
5
|
|
|
5
|
-
#[derive(
|
|
6
|
+
#[derive(
|
|
7
|
+
Hash,
|
|
8
|
+
Eq,
|
|
9
|
+
PartialEq,
|
|
10
|
+
Clone,
|
|
11
|
+
derive_more::From,
|
|
12
|
+
derive_more::Into,
|
|
13
|
+
serde::Serialize,
|
|
14
|
+
serde::Deserialize,
|
|
15
|
+
)]
|
|
6
16
|
/// Type-safe wrapper for task token bytes
|
|
7
17
|
pub struct TaskToken(pub Vec<u8>);
|
|
8
18
|
|
|
@@ -34,5 +44,5 @@ impl Debug for TaskToken {
|
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
pub fn fmt_tt(tt: &[u8]) -> String {
|
|
37
|
-
|
|
47
|
+
BASE64_STANDARD.encode(tt)
|
|
38
48
|
}
|
|
@@ -11,7 +11,8 @@ path = "src/histfetch.rs"
|
|
|
11
11
|
[dependencies]
|
|
12
12
|
anyhow = "1.0"
|
|
13
13
|
async-trait = "0.1"
|
|
14
|
-
base64 = "0.
|
|
14
|
+
base64 = "0.21"
|
|
15
|
+
bytes = "1.3"
|
|
15
16
|
futures = "0.3"
|
|
16
17
|
log = "0.4"
|
|
17
18
|
once_cell = "1.16"
|
|
@@ -19,6 +20,7 @@ parking_lot = "0.12"
|
|
|
19
20
|
prost = "0.11"
|
|
20
21
|
prost-types = "0.11"
|
|
21
22
|
rand = "0.8"
|
|
23
|
+
rmp-serde = "1.1"
|
|
22
24
|
serde_json = "1.0"
|
|
23
25
|
temporal-client = { path = "../client" }
|
|
24
26
|
temporal-sdk = { path = "../sdk" }
|
|
@@ -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;
|
|
@@ -45,7 +51,7 @@ use temporal_sdk_core_protos::{
|
|
|
45
51
|
},
|
|
46
52
|
temporal::api::{common::v1::Payload, history::v1::History},
|
|
47
53
|
};
|
|
48
|
-
use tokio::sync::OnceCell;
|
|
54
|
+
use tokio::sync::{mpsc::unbounded_channel, OnceCell};
|
|
49
55
|
use url::Url;
|
|
50
56
|
|
|
51
57
|
pub const NAMESPACE: &str = "default";
|
|
@@ -61,6 +67,15 @@ pub const INTEG_TEST_SERVER_USED_ENV_VAR: &str = "INTEG_TEST_SERVER_ON";
|
|
|
61
67
|
const OTEL_URL_ENV_VAR: &str = "TEMPORAL_INTEG_OTEL_URL";
|
|
62
68
|
/// If set, enable direct scraping of prom metrics on the specified port
|
|
63
69
|
const PROM_ENABLE_ENV_VAR: &str = "TEMPORAL_INTEG_PROM_PORT";
|
|
70
|
+
#[macro_export]
|
|
71
|
+
macro_rules! prost_dur {
|
|
72
|
+
($dur_call:ident $args:tt) => {
|
|
73
|
+
std::time::Duration::$dur_call$args
|
|
74
|
+
.try_into()
|
|
75
|
+
.expect("test duration fits")
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
64
79
|
/// Create a worker instance which will use the provided test name to base the task queue and wf id
|
|
65
80
|
/// upon. Returns the instance and the task queue name (which is also the workflow id).
|
|
66
81
|
pub async fn init_core_and_create_wf(test_name: &str) -> CoreWfStarter {
|
|
@@ -82,6 +97,7 @@ pub fn init_core_replay_stream<I>(test_name: &str, histories: I) -> Arc<dyn Core
|
|
|
82
97
|
where
|
|
83
98
|
I: Stream<Item = HistoryForReplay> + Send + 'static,
|
|
84
99
|
{
|
|
100
|
+
init_integ_telem();
|
|
85
101
|
let worker_cfg = WorkerConfigBuilder::default()
|
|
86
102
|
.namespace(NAMESPACE)
|
|
87
103
|
.task_queue(test_name)
|
|
@@ -134,7 +150,8 @@ pub struct CoreWfStarter {
|
|
|
134
150
|
/// Used for both the task queue and workflow id
|
|
135
151
|
task_queue_name: String,
|
|
136
152
|
pub worker_config: WorkerConfig,
|
|
137
|
-
|
|
153
|
+
/// Options to use when starting workflow(s)
|
|
154
|
+
pub workflow_options: WorkflowOptions,
|
|
138
155
|
initted_worker: OnceCell<InitializedWorker>,
|
|
139
156
|
}
|
|
140
157
|
struct InitializedWorker {
|
|
@@ -144,14 +161,10 @@ struct InitializedWorker {
|
|
|
144
161
|
|
|
145
162
|
impl CoreWfStarter {
|
|
146
163
|
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
164
|
init_integ_telem();
|
|
165
|
+
let rand_bytes: Vec<u8> = rand::thread_rng().sample_iter(&Standard).take(6).collect();
|
|
166
|
+
let task_q_salt = BASE64_STANDARD.encode(rand_bytes);
|
|
167
|
+
let task_queue = format!("{test_name}_{task_q_salt}");
|
|
155
168
|
Self {
|
|
156
169
|
task_queue_name: task_queue.to_owned(),
|
|
157
170
|
worker_config: WorkerConfigBuilder::default()
|
|
@@ -161,8 +174,8 @@ impl CoreWfStarter {
|
|
|
161
174
|
.max_cached_workflows(1000_usize)
|
|
162
175
|
.build()
|
|
163
176
|
.unwrap(),
|
|
164
|
-
wft_timeout: None,
|
|
165
177
|
initted_worker: OnceCell::new(),
|
|
178
|
+
workflow_options: Default::default(),
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
|
|
@@ -189,13 +202,27 @@ impl CoreWfStarter {
|
|
|
189
202
|
}
|
|
190
203
|
|
|
191
204
|
/// 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()
|
|
205
|
+
pub async fn start_wf(&mut self) -> String {
|
|
206
|
+
self.start_wf_with_id(self.task_queue_name.clone()).await
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
pub async fn start_with_worker(
|
|
210
|
+
&self,
|
|
211
|
+
wf_name: impl Into<String>,
|
|
212
|
+
worker: &mut TestWorker,
|
|
213
|
+
) -> String {
|
|
214
|
+
worker
|
|
215
|
+
.submit_wf(
|
|
216
|
+
self.task_queue_name.clone(),
|
|
217
|
+
wf_name.into(),
|
|
218
|
+
vec![],
|
|
219
|
+
self.workflow_options.clone(),
|
|
220
|
+
)
|
|
194
221
|
.await
|
|
222
|
+
.unwrap()
|
|
195
223
|
}
|
|
196
224
|
|
|
197
|
-
pub async fn start_wf_with_id(&self, workflow_id: String
|
|
198
|
-
opts.task_timeout = opts.task_timeout.or(self.wft_timeout);
|
|
225
|
+
pub async fn start_wf_with_id(&self, workflow_id: String) -> String {
|
|
199
226
|
self.initted_worker
|
|
200
227
|
.get()
|
|
201
228
|
.expect(
|
|
@@ -209,7 +236,7 @@ impl CoreWfStarter {
|
|
|
209
236
|
workflow_id,
|
|
210
237
|
self.task_queue_name.clone(),
|
|
211
238
|
None,
|
|
212
|
-
|
|
239
|
+
self.workflow_options.clone(),
|
|
213
240
|
)
|
|
214
241
|
.await
|
|
215
242
|
.unwrap()
|
|
@@ -274,8 +301,13 @@ impl CoreWfStarter {
|
|
|
274
301
|
self
|
|
275
302
|
}
|
|
276
303
|
|
|
277
|
-
pub fn
|
|
278
|
-
|
|
304
|
+
pub fn enable_wf_state_input_recording(&mut self) -> &mut Self {
|
|
305
|
+
let (ser_tx, ser_rx) = unbounded_channel();
|
|
306
|
+
let worker_cfg_clone = self.worker_config.clone();
|
|
307
|
+
tokio::spawn(async move {
|
|
308
|
+
stream_to_file(&worker_cfg_clone, ser_rx).await.unwrap();
|
|
309
|
+
});
|
|
310
|
+
self.worker_config.wf_state_inputs = Some(ser_tx);
|
|
279
311
|
self
|
|
280
312
|
}
|
|
281
313
|
|
|
@@ -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
|
+
}
|