@temporalio/core-bridge 1.9.0 → 1.9.2
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 +2 -33
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.github/workflows/per-pr.yml +1 -1
- package/sdk-core/Cargo.toml +1 -0
- package/sdk-core/README.md +1 -1
- package/sdk-core/client/src/lib.rs +40 -11
- package/sdk-core/client/src/workflow_handle/mod.rs +4 -0
- package/sdk-core/core/Cargo.toml +3 -2
- package/sdk-core/core/src/core_tests/activity_tasks.rs +69 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +99 -4
- package/sdk-core/core/src/core_tests/queries.rs +90 -1
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +8 -11
- package/sdk-core/core/src/telemetry/metrics.rs +4 -4
- package/sdk-core/core/src/telemetry/mod.rs +1 -3
- package/sdk-core/core/src/test_help/mod.rs +9 -0
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +1 -2
- package/sdk-core/core/src/worker/activities/local_activities.rs +1 -1
- package/sdk-core/core/src/worker/activities.rs +11 -4
- package/sdk-core/core/src/worker/mod.rs +6 -1
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +0 -1
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +28 -6
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +15 -0
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +19 -15
- package/sdk-core/core/src/worker/workflow/mod.rs +89 -59
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +1 -1
- package/sdk-core/core-api/Cargo.toml +2 -2
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +13 -8
- package/sdk-core/sdk/src/workflow_context.rs +2 -2
- package/sdk-core/sdk/src/workflow_future.rs +1 -1
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +16 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +10 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +4 -1
- package/sdk-core/sdk-core-protos/protos/testsrv_upstream/Makefile +3 -10
- package/sdk-core/sdk-core-protos/protos/testsrv_upstream/api-linter.yaml +0 -5
- package/sdk-core/sdk-core-protos/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +3 -4
- package/sdk-core/sdk-core-protos/src/history_info.rs +2 -2
- package/sdk-core/sdk-core-protos/src/lib.rs +1 -0
- package/sdk-core/tests/integ_tests/queries_tests.rs +12 -12
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +48 -0
- package/src/conversions.rs +19 -17
- package/src/runtime.rs +32 -4
- package/sdk-core/sdk-core-protos/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
package/Cargo.lock
CHANGED
|
@@ -331,19 +331,6 @@ dependencies = [
|
|
|
331
331
|
"cfg-if",
|
|
332
332
|
]
|
|
333
333
|
|
|
334
|
-
[[package]]
|
|
335
|
-
name = "crossbeam"
|
|
336
|
-
version = "0.8.4"
|
|
337
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
338
|
-
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
|
|
339
|
-
dependencies = [
|
|
340
|
-
"crossbeam-channel",
|
|
341
|
-
"crossbeam-deque",
|
|
342
|
-
"crossbeam-epoch",
|
|
343
|
-
"crossbeam-queue",
|
|
344
|
-
"crossbeam-utils",
|
|
345
|
-
]
|
|
346
|
-
|
|
347
334
|
[[package]]
|
|
348
335
|
name = "crossbeam-channel"
|
|
349
336
|
version = "0.5.11"
|
|
@@ -353,25 +340,6 @@ dependencies = [
|
|
|
353
340
|
"crossbeam-utils",
|
|
354
341
|
]
|
|
355
342
|
|
|
356
|
-
[[package]]
|
|
357
|
-
name = "crossbeam-deque"
|
|
358
|
-
version = "0.8.5"
|
|
359
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
360
|
-
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
|
361
|
-
dependencies = [
|
|
362
|
-
"crossbeam-epoch",
|
|
363
|
-
"crossbeam-utils",
|
|
364
|
-
]
|
|
365
|
-
|
|
366
|
-
[[package]]
|
|
367
|
-
name = "crossbeam-epoch"
|
|
368
|
-
version = "0.9.18"
|
|
369
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
370
|
-
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
|
371
|
-
dependencies = [
|
|
372
|
-
"crossbeam-utils",
|
|
373
|
-
]
|
|
374
|
-
|
|
375
343
|
[[package]]
|
|
376
344
|
name = "crossbeam-queue"
|
|
377
345
|
version = "0.3.11"
|
|
@@ -2382,7 +2350,8 @@ dependencies = [
|
|
|
2382
2350
|
"arc-swap",
|
|
2383
2351
|
"async-trait",
|
|
2384
2352
|
"base64",
|
|
2385
|
-
"crossbeam",
|
|
2353
|
+
"crossbeam-channel",
|
|
2354
|
+
"crossbeam-queue",
|
|
2386
2355
|
"dashmap",
|
|
2387
2356
|
"derive_builder",
|
|
2388
2357
|
"derive_more",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/core-bridge",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "Temporal.io SDK Core<>Node bridge",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@temporalio/common": "1.9.
|
|
25
|
+
"@temporalio/common": "^1.9.2",
|
|
26
26
|
"arg": "^5.0.2",
|
|
27
27
|
"cargo-cp-artifact": "^0.1.8",
|
|
28
28
|
"which": "^4.0.0"
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "5fd66f5787deece0b30f085808db7651187600b1"
|
|
56
56
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/sdk-core/Cargo.toml
CHANGED
package/sdk-core/README.md
CHANGED
|
@@ -89,7 +89,7 @@ equivalent.
|
|
|
89
89
|
This repo uses a subtree for upstream protobuf files. The path `sdk-core-protos/protos/api_upstream` is a
|
|
90
90
|
subtree. To update it, use:
|
|
91
91
|
|
|
92
|
-
`git pull --squash -s subtree ssh://git@github.com/temporalio/api.git master --allow-unrelated-histories`
|
|
92
|
+
`git pull --squash --rebase=false -s subtree ssh://git@github.com/temporalio/api.git master --allow-unrelated-histories`
|
|
93
93
|
|
|
94
94
|
Do not question why this git command is the way it is. It is not our place to interpret git's ways.
|
|
95
95
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#[macro_use]
|
|
8
8
|
extern crate tracing;
|
|
9
|
+
|
|
9
10
|
mod metrics;
|
|
10
11
|
mod raw;
|
|
11
12
|
mod retry;
|
|
@@ -49,7 +50,7 @@ use temporal_sdk_core_protos::{
|
|
|
49
50
|
coresdk::{workflow_commands::QueryResult, IntoPayloadsExt},
|
|
50
51
|
grpc::health::v1::health_client::HealthClient,
|
|
51
52
|
temporal::api::{
|
|
52
|
-
common::v1::{Header, Payload, Payloads, WorkflowExecution, WorkflowType},
|
|
53
|
+
common::v1::{Header, Payload, Payloads, RetryPolicy, WorkflowExecution, WorkflowType},
|
|
53
54
|
enums::v1::{TaskQueueKind, WorkflowIdReusePolicy},
|
|
54
55
|
failure::v1::Failure,
|
|
55
56
|
operatorservice::v1::operator_service_client::OperatorServiceClient,
|
|
@@ -151,9 +152,9 @@ pub struct TlsConfig {
|
|
|
151
152
|
/// If using mTLS, both the client cert and private key must be specified, this contains them.
|
|
152
153
|
#[derive(Clone)]
|
|
153
154
|
pub struct ClientTlsConfig {
|
|
154
|
-
/// The certificate for this client
|
|
155
|
+
/// The certificate for this client, encoded as PEM
|
|
155
156
|
pub client_cert: Vec<u8>,
|
|
156
|
-
/// The private key for this client
|
|
157
|
+
/// The private key for this client, encoded as PEM
|
|
157
158
|
pub client_private_key: Vec<u8>,
|
|
158
159
|
}
|
|
159
160
|
|
|
@@ -316,6 +317,7 @@ impl<C> Deref for ConfiguredClient<C> {
|
|
|
316
317
|
&self.client
|
|
317
318
|
}
|
|
318
319
|
}
|
|
320
|
+
|
|
319
321
|
impl<C> DerefMut for ConfiguredClient<C> {
|
|
320
322
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
321
323
|
&mut self.client
|
|
@@ -493,6 +495,19 @@ pub struct TemporalServiceClient<T> {
|
|
|
493
495
|
test_svc_client: OnceCell<TestServiceClient<T>>,
|
|
494
496
|
health_svc_client: OnceCell<HealthClient<T>>,
|
|
495
497
|
}
|
|
498
|
+
|
|
499
|
+
/// We up the limit on incoming messages from server from the 4Mb default to 128Mb. If for
|
|
500
|
+
/// whatever reason this needs to be changed by the user, we support overriding it via env var.
|
|
501
|
+
fn get_decode_max_size() -> usize {
|
|
502
|
+
static _DECODE_MAX_SIZE: OnceCell<usize> = OnceCell::new();
|
|
503
|
+
*_DECODE_MAX_SIZE.get_or_init(|| {
|
|
504
|
+
std::env::var("TEMPORAL_MAX_INCOMING_GRPC_BYTES")
|
|
505
|
+
.ok()
|
|
506
|
+
.and_then(|s| s.parse().ok())
|
|
507
|
+
.unwrap_or(128 * 1024 * 1024)
|
|
508
|
+
})
|
|
509
|
+
}
|
|
510
|
+
|
|
496
511
|
impl<T> TemporalServiceClient<T>
|
|
497
512
|
where
|
|
498
513
|
T: Clone,
|
|
@@ -512,23 +527,30 @@ where
|
|
|
512
527
|
}
|
|
513
528
|
/// Get the underlying workflow service client
|
|
514
529
|
pub fn workflow_svc(&self) -> &WorkflowServiceClient<T> {
|
|
515
|
-
self.workflow_svc_client
|
|
516
|
-
|
|
530
|
+
self.workflow_svc_client.get_or_init(|| {
|
|
531
|
+
WorkflowServiceClient::new(self.svc.clone())
|
|
532
|
+
.max_decoding_message_size(get_decode_max_size())
|
|
533
|
+
})
|
|
517
534
|
}
|
|
518
535
|
/// Get the underlying operator service client
|
|
519
536
|
pub fn operator_svc(&self) -> &OperatorServiceClient<T> {
|
|
520
|
-
self.operator_svc_client
|
|
521
|
-
|
|
537
|
+
self.operator_svc_client.get_or_init(|| {
|
|
538
|
+
OperatorServiceClient::new(self.svc.clone())
|
|
539
|
+
.max_decoding_message_size(get_decode_max_size())
|
|
540
|
+
})
|
|
522
541
|
}
|
|
523
542
|
/// Get the underlying test service client
|
|
524
543
|
pub fn test_svc(&self) -> &TestServiceClient<T> {
|
|
525
|
-
self.test_svc_client
|
|
526
|
-
|
|
544
|
+
self.test_svc_client.get_or_init(|| {
|
|
545
|
+
TestServiceClient::new(self.svc.clone())
|
|
546
|
+
.max_decoding_message_size(get_decode_max_size())
|
|
547
|
+
})
|
|
527
548
|
}
|
|
528
549
|
/// Get the underlying health service client
|
|
529
550
|
pub fn health_svc(&self) -> &HealthClient<T> {
|
|
530
|
-
self.health_svc_client
|
|
531
|
-
|
|
551
|
+
self.health_svc_client.get_or_init(|| {
|
|
552
|
+
HealthClient::new(self.svc.clone()).max_decoding_message_size(get_decode_max_size())
|
|
553
|
+
})
|
|
532
554
|
}
|
|
533
555
|
/// Get the underlying workflow service client mutably
|
|
534
556
|
pub fn workflow_svc_mut(&mut self) -> &mut WorkflowServiceClient<T> {
|
|
@@ -551,6 +573,7 @@ where
|
|
|
551
573
|
self.health_svc_client.get_mut().unwrap()
|
|
552
574
|
}
|
|
553
575
|
}
|
|
576
|
+
|
|
554
577
|
/// A [WorkflowServiceClient] with the default interceptors attached.
|
|
555
578
|
pub type WorkflowServiceClientWithMetrics = WorkflowServiceClient<InterceptedMetricsSvc>;
|
|
556
579
|
/// An [OperatorServiceClient] with the default interceptors attached.
|
|
@@ -986,6 +1009,9 @@ pub struct WorkflowOptions {
|
|
|
986
1009
|
/// Optionally enable Eager Workflow Start, a latency optimization using local workers
|
|
987
1010
|
/// NOTE: Experimental and incompatible with versioning with BuildIDs
|
|
988
1011
|
pub enable_eager_workflow_start: bool,
|
|
1012
|
+
|
|
1013
|
+
/// Optionally set a retry policy for the workflow
|
|
1014
|
+
pub retry_policy: Option<RetryPolicy>,
|
|
989
1015
|
}
|
|
990
1016
|
|
|
991
1017
|
#[async_trait::async_trait]
|
|
@@ -1023,6 +1049,7 @@ impl WorkflowClientTrait for Client {
|
|
|
1023
1049
|
search_attributes: options.search_attributes.map(|d| d.into()),
|
|
1024
1050
|
cron_schedule: options.cron_schedule.unwrap_or_default(),
|
|
1025
1051
|
request_eager_execution: options.enable_eager_workflow_start,
|
|
1052
|
+
retry_policy: options.retry_policy,
|
|
1026
1053
|
..Default::default()
|
|
1027
1054
|
},
|
|
1028
1055
|
)
|
|
@@ -1497,6 +1524,7 @@ mod sealed {
|
|
|
1497
1524
|
WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
|
|
1498
1525
|
{
|
|
1499
1526
|
}
|
|
1527
|
+
|
|
1500
1528
|
impl<T> WfHandleClient for T where
|
|
1501
1529
|
T: WorkflowClientTrait + RawClientLike<SvcType = InterceptedMetricsSvc>
|
|
1502
1530
|
{
|
|
@@ -1523,6 +1551,7 @@ pub trait WfClientExt: WfHandleClient + Sized + Clone {
|
|
|
1523
1551
|
)
|
|
1524
1552
|
}
|
|
1525
1553
|
}
|
|
1554
|
+
|
|
1526
1555
|
impl<T> WfClientExt for T where T: WfHandleClient + Clone + Sized {}
|
|
1527
1556
|
|
|
1528
1557
|
#[cfg(test)]
|
package/sdk-core/core/Cargo.toml
CHANGED
|
@@ -27,10 +27,11 @@ arc-swap = "1.3"
|
|
|
27
27
|
async-trait = "0.1"
|
|
28
28
|
base64 = "0.21"
|
|
29
29
|
console-subscriber = { version = "0.1", optional = true }
|
|
30
|
-
crossbeam = "0.
|
|
30
|
+
crossbeam-channel = "0.5"
|
|
31
|
+
crossbeam-queue = "0.3"
|
|
31
32
|
dashmap = "5.5"
|
|
32
33
|
derive_builder = "0.12"
|
|
33
|
-
derive_more =
|
|
34
|
+
derive_more = { workspace = true }
|
|
34
35
|
enum_dispatch = "0.3"
|
|
35
36
|
enum-iterator = "1.4"
|
|
36
37
|
flate2 = { version = "1.0", optional = true }
|
|
@@ -17,7 +17,7 @@ use std::{
|
|
|
17
17
|
future,
|
|
18
18
|
rc::Rc,
|
|
19
19
|
sync::{
|
|
20
|
-
atomic::{AtomicUsize, Ordering},
|
|
20
|
+
atomic::{AtomicBool, AtomicUsize, Ordering},
|
|
21
21
|
Arc,
|
|
22
22
|
},
|
|
23
23
|
time::Duration,
|
|
@@ -1057,7 +1057,6 @@ async fn cant_complete_activity_with_unset_result_payload() {
|
|
|
1057
1057
|
#[rstest::rstest]
|
|
1058
1058
|
#[tokio::test]
|
|
1059
1059
|
async fn graceful_shutdown(#[values(true, false)] at_max_outstanding: bool) {
|
|
1060
|
-
let _task_q = "q";
|
|
1061
1060
|
let grace_period = Duration::from_millis(200);
|
|
1062
1061
|
let mut tasks = three_tasks();
|
|
1063
1062
|
let mut mock_act_poller = mock_poller();
|
|
@@ -1122,3 +1121,71 @@ async fn graceful_shutdown(#[values(true, false)] at_max_outstanding: bool) {
|
|
|
1122
1121
|
}
|
|
1123
1122
|
worker.drain_pollers_and_shutdown().await;
|
|
1124
1123
|
}
|
|
1124
|
+
|
|
1125
|
+
#[rstest::rstest]
|
|
1126
|
+
#[tokio::test]
|
|
1127
|
+
async fn activities_must_be_flushed_to_server_on_shutdown(#[values(true, false)] use_grace: bool) {
|
|
1128
|
+
let grace_period = if use_grace {
|
|
1129
|
+
// Even though the grace period is shorter than the client call, the client call will still
|
|
1130
|
+
// go through. This is reasonable since the client has a timeout anyway, and it's unlikely
|
|
1131
|
+
// that a user *needs* an extremely short grace period (it'd be kind of pointless in that
|
|
1132
|
+
// case). They can always force-kill their worker in this situation.
|
|
1133
|
+
Duration::from_millis(50)
|
|
1134
|
+
} else {
|
|
1135
|
+
Duration::from_secs(10)
|
|
1136
|
+
};
|
|
1137
|
+
let shutdown_finished: &'static AtomicBool = Box::leak(Box::new(AtomicBool::new(false)));
|
|
1138
|
+
let mut tasks = three_tasks();
|
|
1139
|
+
let mut mock_act_poller = mock_poller();
|
|
1140
|
+
mock_act_poller
|
|
1141
|
+
.expect_poll()
|
|
1142
|
+
.times(1)
|
|
1143
|
+
.returning(move || Some(Ok(tasks.pop_front().unwrap())));
|
|
1144
|
+
mock_act_poller
|
|
1145
|
+
.expect_poll()
|
|
1146
|
+
.times(1)
|
|
1147
|
+
.returning(move || None);
|
|
1148
|
+
let mut mock_client = mock_manual_workflow_client();
|
|
1149
|
+
mock_client
|
|
1150
|
+
.expect_complete_activity_task()
|
|
1151
|
+
.times(1)
|
|
1152
|
+
.returning(|_, _| {
|
|
1153
|
+
async {
|
|
1154
|
+
// We need some artificial delay here and there's nothing meaningful to sync with
|
|
1155
|
+
tokio::time::sleep(Duration::from_millis(100)).await;
|
|
1156
|
+
if shutdown_finished.load(Ordering::Acquire) {
|
|
1157
|
+
panic!("Shutdown must complete *after* server sees the activity completion");
|
|
1158
|
+
}
|
|
1159
|
+
Ok(Default::default())
|
|
1160
|
+
}
|
|
1161
|
+
.boxed()
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
let mw = MockWorkerInputs {
|
|
1165
|
+
act_poller: Some(Box::from(mock_act_poller)),
|
|
1166
|
+
config: test_worker_cfg()
|
|
1167
|
+
.graceful_shutdown_period(grace_period)
|
|
1168
|
+
.max_concurrent_at_polls(1_usize) // Makes test logic simple
|
|
1169
|
+
.build()
|
|
1170
|
+
.unwrap(),
|
|
1171
|
+
..Default::default()
|
|
1172
|
+
};
|
|
1173
|
+
let worker = mock_worker(MocksHolder::from_mock_worker(mock_client, mw));
|
|
1174
|
+
|
|
1175
|
+
let task = worker.poll_activity_task().await.unwrap();
|
|
1176
|
+
|
|
1177
|
+
let shutdown_task = async {
|
|
1178
|
+
worker.drain_activity_poller_and_shutdown().await;
|
|
1179
|
+
shutdown_finished.store(true, Ordering::Release);
|
|
1180
|
+
};
|
|
1181
|
+
let complete_task = async {
|
|
1182
|
+
worker
|
|
1183
|
+
.complete_activity_task(ActivityTaskCompletion {
|
|
1184
|
+
task_token: task.task_token,
|
|
1185
|
+
result: Some(ActivityExecutionResult::ok("hi".into())),
|
|
1186
|
+
})
|
|
1187
|
+
.await
|
|
1188
|
+
.unwrap();
|
|
1189
|
+
};
|
|
1190
|
+
join!(shutdown_task, complete_task);
|
|
1191
|
+
}
|
|
@@ -2,13 +2,13 @@ use crate::{
|
|
|
2
2
|
prost_dur,
|
|
3
3
|
replay::{default_wes_attribs, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE},
|
|
4
4
|
test_help::{
|
|
5
|
-
hist_to_poll_resp, mock_sdk, mock_sdk_cfg, mock_worker,
|
|
6
|
-
ResponseType, WorkerExt,
|
|
5
|
+
build_mock_pollers, hist_to_poll_resp, mock_sdk, mock_sdk_cfg, mock_worker,
|
|
6
|
+
single_hist_mock_sg, MockPollCfg, ResponseType, WorkerExt,
|
|
7
7
|
},
|
|
8
8
|
worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
|
|
9
9
|
};
|
|
10
10
|
use anyhow::anyhow;
|
|
11
|
-
use
|
|
11
|
+
use crossbeam_queue::SegQueue;
|
|
12
12
|
use futures::{future::join_all, FutureExt};
|
|
13
13
|
use std::{
|
|
14
14
|
collections::HashMap,
|
|
@@ -38,7 +38,7 @@ use temporal_sdk_core_protos::{
|
|
|
38
38
|
},
|
|
39
39
|
temporal::api::{
|
|
40
40
|
common::v1::RetryPolicy,
|
|
41
|
-
enums::v1::{EventType, TimeoutType, WorkflowTaskFailedCause},
|
|
41
|
+
enums::v1::{CommandType, EventType, TimeoutType, WorkflowTaskFailedCause},
|
|
42
42
|
failure::v1::{failure::FailureInfo, Failure},
|
|
43
43
|
query::v1::WorkflowQuery,
|
|
44
44
|
},
|
|
@@ -1295,3 +1295,98 @@ async fn queries_can_be_received_while_heartbeating() {
|
|
|
1295
1295
|
|
|
1296
1296
|
core.drain_pollers_and_shutdown().await;
|
|
1297
1297
|
}
|
|
1298
|
+
|
|
1299
|
+
#[tokio::test]
|
|
1300
|
+
async fn local_activity_after_wf_complete_is_discarded() {
|
|
1301
|
+
let wfid = "fake_wf_id";
|
|
1302
|
+
let mut t = TestHistoryBuilder::default();
|
|
1303
|
+
t.add_wfe_started_with_wft_timeout(Duration::from_millis(200));
|
|
1304
|
+
t.add_full_wf_task();
|
|
1305
|
+
t.add_workflow_task_scheduled_and_started();
|
|
1306
|
+
|
|
1307
|
+
let mock = mock_workflow_client();
|
|
1308
|
+
let mut mock_cfg = MockPollCfg::from_resp_batches(
|
|
1309
|
+
wfid,
|
|
1310
|
+
t,
|
|
1311
|
+
[ResponseType::ToTaskNum(1), ResponseType::ToTaskNum(2)],
|
|
1312
|
+
mock,
|
|
1313
|
+
);
|
|
1314
|
+
mock_cfg.make_poll_stream_interminable = true;
|
|
1315
|
+
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
|
|
1316
|
+
asserts
|
|
1317
|
+
.then(move |wft| {
|
|
1318
|
+
assert_eq!(wft.commands.len(), 0);
|
|
1319
|
+
})
|
|
1320
|
+
.then(move |wft| {
|
|
1321
|
+
assert_eq!(wft.commands.len(), 2);
|
|
1322
|
+
assert_eq!(wft.commands[0].command_type(), CommandType::RecordMarker);
|
|
1323
|
+
assert_eq!(
|
|
1324
|
+
wft.commands[1].command_type(),
|
|
1325
|
+
CommandType::CompleteWorkflowExecution
|
|
1326
|
+
);
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
let mut mock = build_mock_pollers(mock_cfg);
|
|
1330
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
1331
|
+
let core = mock_worker(mock);
|
|
1332
|
+
|
|
1333
|
+
let barr = Barrier::new(2);
|
|
1334
|
+
|
|
1335
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
1336
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmds(
|
|
1337
|
+
task.run_id,
|
|
1338
|
+
vec![
|
|
1339
|
+
ScheduleLocalActivity {
|
|
1340
|
+
seq: 1,
|
|
1341
|
+
activity_id: "1".to_string(),
|
|
1342
|
+
activity_type: "test_act".to_string(),
|
|
1343
|
+
start_to_close_timeout: Some(prost_dur!(from_secs(30))),
|
|
1344
|
+
..Default::default()
|
|
1345
|
+
}
|
|
1346
|
+
.into(),
|
|
1347
|
+
ScheduleLocalActivity {
|
|
1348
|
+
seq: 2,
|
|
1349
|
+
activity_id: "2".to_string(),
|
|
1350
|
+
activity_type: "test_act".to_string(),
|
|
1351
|
+
start_to_close_timeout: Some(prost_dur!(from_secs(30))),
|
|
1352
|
+
..Default::default()
|
|
1353
|
+
}
|
|
1354
|
+
.into(),
|
|
1355
|
+
],
|
|
1356
|
+
))
|
|
1357
|
+
.await
|
|
1358
|
+
.unwrap();
|
|
1359
|
+
|
|
1360
|
+
let wf_poller = async {
|
|
1361
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
1362
|
+
assert_matches!(
|
|
1363
|
+
task.jobs.as_slice(),
|
|
1364
|
+
[WorkflowActivationJob {
|
|
1365
|
+
variant: Some(workflow_activation_job::Variant::ResolveActivity(_)),
|
|
1366
|
+
}]
|
|
1367
|
+
);
|
|
1368
|
+
barr.wait().await;
|
|
1369
|
+
core.complete_execution(&task.run_id).await;
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
let at_poller = async {
|
|
1373
|
+
let act_task = core.poll_activity_task().await.unwrap();
|
|
1374
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
1375
|
+
task_token: act_task.task_token,
|
|
1376
|
+
result: Some(ActivityExecutionResult::ok(vec![1].into())),
|
|
1377
|
+
})
|
|
1378
|
+
.await
|
|
1379
|
+
.unwrap();
|
|
1380
|
+
let act_task = core.poll_activity_task().await.unwrap();
|
|
1381
|
+
barr.wait().await;
|
|
1382
|
+
core.complete_activity_task(ActivityTaskCompletion {
|
|
1383
|
+
task_token: act_task.task_token,
|
|
1384
|
+
result: Some(ActivityExecutionResult::ok(vec![2].into())),
|
|
1385
|
+
})
|
|
1386
|
+
.await
|
|
1387
|
+
.unwrap();
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1390
|
+
join!(wf_poller, at_poller);
|
|
1391
|
+
core.drain_pollers_and_shutdown().await;
|
|
1392
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
test_help::{
|
|
3
3
|
build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, single_hist_mock_sg,
|
|
4
|
-
MockPollCfg, ResponseType, WorkerExt,
|
|
4
|
+
MockPollCfg, MocksHolder, ResponseType, WorkerExt,
|
|
5
5
|
},
|
|
6
6
|
worker::{client::mocks::mock_workflow_client, LEGACY_QUERY_ID},
|
|
7
7
|
};
|
|
8
|
+
use futures_util::stream;
|
|
8
9
|
use std::{
|
|
9
10
|
collections::{HashMap, VecDeque},
|
|
10
11
|
time::Duration,
|
|
@@ -891,3 +892,91 @@ async fn build_id_set_properly_on_query_on_first_task() {
|
|
|
891
892
|
.unwrap();
|
|
892
893
|
core.drain_pollers_and_shutdown().await;
|
|
893
894
|
}
|
|
895
|
+
|
|
896
|
+
#[tokio::test]
|
|
897
|
+
async fn queries_arent_lost_in_buffer_void() {
|
|
898
|
+
let wfid = "fake_wf_id";
|
|
899
|
+
let mut t = TestHistoryBuilder::default();
|
|
900
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
901
|
+
t.add_full_wf_task();
|
|
902
|
+
t.add_we_signaled("sig", vec![]);
|
|
903
|
+
t.add_full_wf_task();
|
|
904
|
+
t.add_workflow_execution_completed();
|
|
905
|
+
let tasks = [
|
|
906
|
+
hist_to_poll_resp(&t, wfid.to_owned(), 1.into()),
|
|
907
|
+
{
|
|
908
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
|
|
909
|
+
pr.query = Some(WorkflowQuery {
|
|
910
|
+
query_type: "1".to_string(),
|
|
911
|
+
..Default::default()
|
|
912
|
+
});
|
|
913
|
+
pr.started_event_id = 0;
|
|
914
|
+
pr
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 1.into());
|
|
918
|
+
pr.query = Some(WorkflowQuery {
|
|
919
|
+
query_type: "2".to_string(),
|
|
920
|
+
..Default::default()
|
|
921
|
+
});
|
|
922
|
+
pr.started_event_id = 0;
|
|
923
|
+
pr
|
|
924
|
+
},
|
|
925
|
+
hist_to_poll_resp(&t, wfid.to_owned(), 2.into()),
|
|
926
|
+
]
|
|
927
|
+
.map(|r| r.resp);
|
|
928
|
+
|
|
929
|
+
let mut mock = mock_workflow_client();
|
|
930
|
+
mock.expect_complete_workflow_task()
|
|
931
|
+
.returning(|_| Ok(Default::default()));
|
|
932
|
+
mock.expect_respond_legacy_query()
|
|
933
|
+
.times(2)
|
|
934
|
+
.returning(|_, _| Ok(Default::default()));
|
|
935
|
+
let mut mock = MocksHolder::from_wft_stream(mock, stream::iter(tasks));
|
|
936
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 1);
|
|
937
|
+
let core = mock_worker(mock);
|
|
938
|
+
|
|
939
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
940
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::empty(task.run_id))
|
|
941
|
+
.await
|
|
942
|
+
.unwrap();
|
|
943
|
+
|
|
944
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
945
|
+
assert_matches!(
|
|
946
|
+
task.jobs.as_slice(),
|
|
947
|
+
[WorkflowActivationJob {
|
|
948
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
949
|
+
}] => q.query_type == "1"
|
|
950
|
+
);
|
|
951
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
952
|
+
task.run_id,
|
|
953
|
+
query_ok(LEGACY_QUERY_ID.to_string(), "hi"),
|
|
954
|
+
))
|
|
955
|
+
.await
|
|
956
|
+
.unwrap();
|
|
957
|
+
|
|
958
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
959
|
+
assert_matches!(
|
|
960
|
+
task.jobs.as_slice(),
|
|
961
|
+
[WorkflowActivationJob {
|
|
962
|
+
variant: Some(workflow_activation_job::Variant::QueryWorkflow(q)),
|
|
963
|
+
}] => q.query_type == "2"
|
|
964
|
+
);
|
|
965
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
966
|
+
task.run_id,
|
|
967
|
+
query_ok(LEGACY_QUERY_ID.to_string(), "hi"),
|
|
968
|
+
))
|
|
969
|
+
.await
|
|
970
|
+
.unwrap();
|
|
971
|
+
|
|
972
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
973
|
+
assert_matches!(
|
|
974
|
+
task.jobs.as_slice(),
|
|
975
|
+
[WorkflowActivationJob {
|
|
976
|
+
variant: Some(workflow_activation_job::Variant::SignalWorkflow(_)),
|
|
977
|
+
}]
|
|
978
|
+
);
|
|
979
|
+
core.complete_execution(&task.run_id).await;
|
|
980
|
+
|
|
981
|
+
core.shutdown().await;
|
|
982
|
+
}
|
|
@@ -2112,15 +2112,12 @@ async fn continue_as_new_preserves_some_values() {
|
|
|
2112
2112
|
wes_attrs.search_attributes = Some(search);
|
|
2113
2113
|
wes_attrs.retry_policy = Some(retry_policy);
|
|
2114
2114
|
let mut mock_client = mock_workflow_client();
|
|
2115
|
-
let
|
|
2115
|
+
let t = {
|
|
2116
2116
|
let mut t = TestHistoryBuilder::default();
|
|
2117
2117
|
t.add(wes_attrs.clone());
|
|
2118
2118
|
t.add_full_wf_task();
|
|
2119
2119
|
t
|
|
2120
2120
|
};
|
|
2121
|
-
mock_client.expect_poll_workflow_task().returning(move |_| {
|
|
2122
|
-
Ok(hist_to_poll_resp(&hist, wfid.to_owned(), ResponseType::AllHistory).resp)
|
|
2123
|
-
});
|
|
2124
2121
|
mock_client
|
|
2125
2122
|
.expect_complete_workflow_task()
|
|
2126
2123
|
.returning(move |mut c| {
|
|
@@ -2135,8 +2132,8 @@ async fn continue_as_new_preserves_some_values() {
|
|
|
2135
2132
|
}
|
|
2136
2133
|
Ok(Default::default())
|
|
2137
2134
|
});
|
|
2138
|
-
|
|
2139
|
-
let worker =
|
|
2135
|
+
let mock = single_hist_mock_sg(wfid, t, vec![ResponseType::AllHistory], mock_client, true);
|
|
2136
|
+
let worker = mock_worker(mock);
|
|
2140
2137
|
let r = worker.poll_workflow_activation().await.unwrap();
|
|
2141
2138
|
worker
|
|
2142
2139
|
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
@@ -2149,6 +2146,7 @@ async fn continue_as_new_preserves_some_values() {
|
|
|
2149
2146
|
))
|
|
2150
2147
|
.await
|
|
2151
2148
|
.unwrap();
|
|
2149
|
+
worker.shutdown().await;
|
|
2152
2150
|
}
|
|
2153
2151
|
|
|
2154
2152
|
#[rstest]
|
|
@@ -2737,15 +2735,12 @@ async fn use_compatible_version_flag(
|
|
|
2737
2735
|
) {
|
|
2738
2736
|
let wfid = "fake_wf_id";
|
|
2739
2737
|
let mut mock_client = mock_workflow_client();
|
|
2740
|
-
let
|
|
2738
|
+
let t = {
|
|
2741
2739
|
let mut t = TestHistoryBuilder::default();
|
|
2742
2740
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
2743
2741
|
t.add_full_wf_task();
|
|
2744
2742
|
t
|
|
2745
2743
|
};
|
|
2746
|
-
mock_client.expect_poll_workflow_task().returning(move |_| {
|
|
2747
|
-
Ok(hist_to_poll_resp(&hist, wfid.to_owned(), ResponseType::AllHistory).resp)
|
|
2748
|
-
});
|
|
2749
2744
|
let compat_flag_expected = match intent {
|
|
2750
2745
|
VersioningIntent::Unspecified => !different_tq,
|
|
2751
2746
|
VersioningIntent::Compatible => true,
|
|
@@ -2770,7 +2765,8 @@ async fn use_compatible_version_flag(
|
|
|
2770
2765
|
Ok(Default::default())
|
|
2771
2766
|
});
|
|
2772
2767
|
|
|
2773
|
-
let
|
|
2768
|
+
let mock = single_hist_mock_sg(wfid, t, vec![ResponseType::AllHistory], mock_client, true);
|
|
2769
|
+
let worker = mock_worker(mock);
|
|
2774
2770
|
let r = worker.poll_workflow_activation().await.unwrap();
|
|
2775
2771
|
let task_queue = if different_tq {
|
|
2776
2772
|
"enchi cat!".to_string()
|
|
@@ -2806,6 +2802,7 @@ async fn use_compatible_version_flag(
|
|
|
2806
2802
|
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(r.run_id, cmd))
|
|
2807
2803
|
.await
|
|
2808
2804
|
.unwrap();
|
|
2805
|
+
worker.shutdown().await;
|
|
2809
2806
|
}
|
|
2810
2807
|
|
|
2811
2808
|
#[tokio::test]
|