@temporalio/core-bridge 1.8.3 → 1.8.4
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/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/core/src/core_tests/replay_flag.rs +73 -3
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +21 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/core-bridge",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
4
4
|
"description": "Temporal.io SDK Core<>Node bridge",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@opentelemetry/api": "^1.4.1",
|
|
26
|
-
"@temporalio/common": "1.8.
|
|
26
|
+
"@temporalio/common": "1.8.4",
|
|
27
27
|
"arg": "^5.0.2",
|
|
28
28
|
"cargo-cp-artifact": "^0.1.6",
|
|
29
29
|
"which": "^2.0.2"
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "7e65cf816b1deef72973dc64ccbf2c93916a3eb1"
|
|
57
57
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
use crate::{
|
|
1
|
+
use crate::{
|
|
2
|
+
test_help::{
|
|
3
|
+
build_mock_pollers, canned_histories, hist_to_poll_resp, mock_worker, MockPollCfg,
|
|
4
|
+
},
|
|
5
|
+
worker::{client::mocks::mock_workflow_client, ManagedWFFunc, LEGACY_QUERY_ID},
|
|
6
|
+
};
|
|
2
7
|
use rstest::{fixture, rstest};
|
|
3
|
-
use std::time::Duration;
|
|
8
|
+
use std::{collections::VecDeque, time::Duration};
|
|
4
9
|
use temporal_sdk::{WfContext, WorkflowFunction};
|
|
5
|
-
use
|
|
10
|
+
use temporal_sdk_core_api::Worker;
|
|
11
|
+
use temporal_sdk_core_protos::{
|
|
12
|
+
coresdk::{
|
|
13
|
+
workflow_commands::{workflow_command::Variant::RespondToQuery, QueryResult, QuerySuccess},
|
|
14
|
+
workflow_completion::WorkflowActivationCompletion,
|
|
15
|
+
},
|
|
16
|
+
temporal::api::{enums::v1::CommandType, query::v1::WorkflowQuery},
|
|
17
|
+
};
|
|
18
|
+
use temporal_sdk_core_test_utils::start_timer_cmd;
|
|
6
19
|
|
|
7
20
|
fn timers_wf(num_timers: u32) -> WorkflowFunction {
|
|
8
21
|
WorkflowFunction::new(move |command_sink: WfContext| async move {
|
|
@@ -63,3 +76,60 @@ async fn replay_flag_is_correct_partial_history() {
|
|
|
63
76
|
assert_eq!(commands[0].command_type, CommandType::StartTimer as i32);
|
|
64
77
|
wfm.shutdown().await.unwrap();
|
|
65
78
|
}
|
|
79
|
+
|
|
80
|
+
#[tokio::test]
|
|
81
|
+
async fn replay_flag_correct_with_query() {
|
|
82
|
+
let wfid = "fake_wf_id";
|
|
83
|
+
let t = canned_histories::single_timer("1");
|
|
84
|
+
let tasks = VecDeque::from(vec![
|
|
85
|
+
{
|
|
86
|
+
let mut pr = hist_to_poll_resp(&t, wfid.to_owned(), 2.into());
|
|
87
|
+
// Server can issue queries that contain the WFT completion and the subsequent
|
|
88
|
+
// commands, but not the consequences yet.
|
|
89
|
+
pr.query = Some(WorkflowQuery {
|
|
90
|
+
query_type: "query-type".to_string(),
|
|
91
|
+
query_args: Some(b"hi".into()),
|
|
92
|
+
header: None,
|
|
93
|
+
});
|
|
94
|
+
let h = pr.history.as_mut().unwrap();
|
|
95
|
+
h.events.truncate(5);
|
|
96
|
+
pr.started_event_id = 3;
|
|
97
|
+
dbg!(&pr.resp);
|
|
98
|
+
pr
|
|
99
|
+
},
|
|
100
|
+
hist_to_poll_resp(&t, wfid.to_owned(), 2.into()),
|
|
101
|
+
]);
|
|
102
|
+
let mut mock = MockPollCfg::from_resp_batches(wfid, t, tasks, mock_workflow_client());
|
|
103
|
+
mock.num_expected_legacy_query_resps = 1;
|
|
104
|
+
let mut mock = build_mock_pollers(mock);
|
|
105
|
+
mock.worker_cfg(|wc| wc.max_cached_workflows = 10);
|
|
106
|
+
let core = mock_worker(mock);
|
|
107
|
+
|
|
108
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
109
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
110
|
+
task.run_id,
|
|
111
|
+
start_timer_cmd(1, Duration::from_secs(1)),
|
|
112
|
+
))
|
|
113
|
+
.await
|
|
114
|
+
.unwrap();
|
|
115
|
+
|
|
116
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
117
|
+
assert!(task.is_replaying);
|
|
118
|
+
core.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
119
|
+
task.run_id,
|
|
120
|
+
RespondToQuery(QueryResult {
|
|
121
|
+
query_id: LEGACY_QUERY_ID.to_string(),
|
|
122
|
+
variant: Some(
|
|
123
|
+
QuerySuccess {
|
|
124
|
+
response: Some("hi".into()),
|
|
125
|
+
}
|
|
126
|
+
.into(),
|
|
127
|
+
),
|
|
128
|
+
}),
|
|
129
|
+
))
|
|
130
|
+
.await
|
|
131
|
+
.unwrap();
|
|
132
|
+
|
|
133
|
+
let task = core.poll_workflow_activation().await.unwrap();
|
|
134
|
+
assert!(!task.is_replaying);
|
|
135
|
+
}
|
|
@@ -367,9 +367,17 @@ impl WorkflowMachines {
|
|
|
367
367
|
/// "no work" situation. Possibly, it may know about some work the machines don't, like queries.
|
|
368
368
|
pub(crate) fn get_wf_activation(&mut self) -> WorkflowActivation {
|
|
369
369
|
let jobs = self.drive_me.drain_jobs();
|
|
370
|
+
// Even though technically we may have satisfied all the criteria to be done with replay,
|
|
371
|
+
// query only activations are always "replaying" to keep things sane.
|
|
372
|
+
let all_query = jobs.iter().all(|j| {
|
|
373
|
+
matches!(
|
|
374
|
+
j.variant,
|
|
375
|
+
Some(workflow_activation_job::Variant::QueryWorkflow(_))
|
|
376
|
+
)
|
|
377
|
+
});
|
|
370
378
|
WorkflowActivation {
|
|
371
379
|
timestamp: self.current_wf_time.map(Into::into),
|
|
372
|
-
is_replaying: self.replaying,
|
|
380
|
+
is_replaying: self.replaying || all_query,
|
|
373
381
|
run_id: self.run_id.clone(),
|
|
374
382
|
history_length: self.last_processed_event as u32,
|
|
375
383
|
jobs,
|
|
@@ -488,7 +496,6 @@ impl WorkflowMachines {
|
|
|
488
496
|
}
|
|
489
497
|
}
|
|
490
498
|
|
|
491
|
-
let mut saw_completed = false;
|
|
492
499
|
let mut do_handle_event = true;
|
|
493
500
|
let mut history = events.into_iter().peekable();
|
|
494
501
|
while let Some(event) = history.next() {
|
|
@@ -504,17 +511,21 @@ impl WorkflowMachines {
|
|
|
504
511
|
// This definition of replaying here is that we are no longer replaying as soon as we
|
|
505
512
|
// see new events that have never been seen or produced by the SDK.
|
|
506
513
|
//
|
|
507
|
-
// Specifically, replay ends once we have seen
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
|
|
514
|
+
// Specifically, replay ends once we have seen any non-command event (IE: events that
|
|
515
|
+
// aren't a result of something we produced in the SDK) on a WFT which has the final
|
|
516
|
+
// event in history (meaning we are processing the most recent WFT and there are no
|
|
517
|
+
// more subsequent WFTs). WFT Completed in this case does not count as a non-command
|
|
518
|
+
// event, because that will typically show up as the first event in an incremental
|
|
519
|
+
// history, and we want to ignore it and its associated commands since we "produced"
|
|
520
|
+
// them.
|
|
521
|
+
if self.replaying
|
|
522
|
+
&& has_final_event
|
|
523
|
+
&& event.event_type() != EventType::WorkflowTaskCompleted
|
|
524
|
+
&& !event.is_command_event()
|
|
525
|
+
{
|
|
512
526
|
// Replay is finished
|
|
513
527
|
self.replaying = false;
|
|
514
528
|
}
|
|
515
|
-
if event.event_type() == EventType::WorkflowTaskCompleted {
|
|
516
|
-
saw_completed = true;
|
|
517
|
-
}
|
|
518
529
|
|
|
519
530
|
if do_handle_event {
|
|
520
531
|
let eho = self.handle_event(
|