@temporalio/core-bridge 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +520 -456
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +8 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +1 -1
- package/sdk-core/.github/workflows/heavy.yml +1 -0
- package/sdk-core/README.md +13 -7
- package/sdk-core/client/src/lib.rs +27 -9
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +3 -3
- package/sdk-core/core/Cargo.toml +3 -4
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +197 -18
- package/sdk-core/core/src/core_tests/activity_tasks.rs +137 -45
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +212 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +183 -36
- package/sdk-core/core/src/core_tests/queries.rs +32 -14
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +340 -51
- package/sdk-core/core/src/ephemeral_server/mod.rs +110 -8
- package/sdk-core/core/src/internal_flags.rs +141 -0
- package/sdk-core/core/src/lib.rs +14 -9
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +38 -14
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +65 -13
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +119 -160
- package/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- package/sdk-core/core/src/worker/activities/local_activities.rs +122 -6
- package/sdk-core/core/src/worker/activities.rs +347 -173
- package/sdk-core/core/src/worker/client/mocks.rs +22 -2
- package/sdk-core/core/src/worker/client.rs +18 -2
- package/sdk-core/core/src/worker/mod.rs +137 -44
- package/sdk-core/core/src/worker/workflow/history_update.rs +132 -51
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +207 -166
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +157 -82
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +12 -12
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +6 -7
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +13 -15
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +170 -60
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +24 -16
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +6 -8
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +320 -204
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +10 -13
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +15 -23
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +187 -46
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +237 -111
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +13 -13
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +10 -6
- package/sdk-core/core/src/worker/workflow/managed_run.rs +81 -62
- package/sdk-core/core/src/worker/workflow/mod.rs +341 -79
- package/sdk-core/core/src/worker/workflow/run_cache.rs +18 -11
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +15 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +75 -52
- package/sdk-core/core-api/Cargo.toml +0 -1
- package/sdk-core/core-api/src/lib.rs +13 -7
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +80 -55
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +22 -68
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/old_change_marker_format.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +2 -1
- package/sdk-core/protos/api_upstream/Makefile +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +7 -8
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +10 -7
- package/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +19 -30
- package/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +8 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +65 -60
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +85 -84
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +9 -3
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +21 -5
- package/sdk-core/sdk/src/workflow_context/options.rs +7 -1
- package/sdk-core/sdk/src/workflow_context.rs +24 -17
- package/sdk-core/sdk/src/workflow_future.rs +9 -3
- package/sdk-core/sdk-core-protos/src/history_builder.rs +114 -89
- package/sdk-core/sdk-core-protos/src/history_info.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +205 -64
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/lib.rs +32 -5
- package/sdk-core/tests/heavy_tests.rs +10 -43
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +3 -8
- package/sdk-core/tests/integ_tests/queries_tests.rs +4 -2
- package/sdk-core/tests/integ_tests/visibility_tests.rs +34 -23
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +97 -81
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +80 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -1
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +25 -3
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +30 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +64 -0
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +4 -0
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +3 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +7 -2
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -7
- package/sdk-core/tests/integ_tests/workflow_tests.rs +8 -8
- package/sdk-core/tests/main.rs +16 -25
- package/sdk-core/tests/runner.rs +11 -9
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
|
@@ -19,15 +19,15 @@ use std::{
|
|
|
19
19
|
};
|
|
20
20
|
use temporal_sdk_core_protos::temporal::api::{
|
|
21
21
|
enums::v1::EventType,
|
|
22
|
-
history::v1::{History, HistoryEvent},
|
|
22
|
+
history::v1::{history_event, History, HistoryEvent, WorkflowTaskCompletedEventAttributes},
|
|
23
23
|
};
|
|
24
24
|
use tracing::Instrument;
|
|
25
25
|
|
|
26
26
|
lazy_static::lazy_static! {
|
|
27
27
|
static ref EMPTY_FETCH_ERR: tonic::Status
|
|
28
|
-
= tonic::Status::
|
|
28
|
+
= tonic::Status::unknown("Fetched empty history page");
|
|
29
29
|
static ref EMPTY_TASK_ERR: tonic::Status
|
|
30
|
-
= tonic::Status::
|
|
30
|
+
= tonic::Status::unknown("Received an empty workflow task with no queries or history");
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/// Represents one or more complete WFT sequences. History events are expected to be consumed from
|
|
@@ -42,6 +42,9 @@ pub struct HistoryUpdate {
|
|
|
42
42
|
/// extracted from. Hence, while processing multiple logical WFTs during replay which were part
|
|
43
43
|
/// of one large history fetched from server, multiple updates may have the same value here.
|
|
44
44
|
pub previous_wft_started_id: i64,
|
|
45
|
+
/// The `started_event_id` field from the WFT which this update is tied to. Multiple updates
|
|
46
|
+
/// may have the same value if they're associated with the same WFT.
|
|
47
|
+
pub wft_started_id: i64,
|
|
45
48
|
/// True if this update contains the final WFT in history, and no more attempts to extract
|
|
46
49
|
/// additional updates should be made.
|
|
47
50
|
has_last_wft: bool,
|
|
@@ -61,28 +64,11 @@ impl Debug for HistoryUpdate {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
|
-
impl HistoryUpdate {
|
|
65
|
-
/// Sometimes it's useful to take an update out of something without needing to use an option
|
|
66
|
-
/// field. Use this to replace the field with an empty update.
|
|
67
|
-
pub fn dummy() -> Self {
|
|
68
|
-
Self {
|
|
69
|
-
events: vec![],
|
|
70
|
-
previous_wft_started_id: -1,
|
|
71
|
-
has_last_wft: false,
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
pub fn is_real(&self) -> bool {
|
|
75
|
-
self.previous_wft_started_id >= 0
|
|
76
|
-
}
|
|
77
|
-
pub fn first_event_id(&self) -> Option<i64> {
|
|
78
|
-
self.events.get(0).map(|e| e.event_id)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
67
|
|
|
82
68
|
#[derive(Debug)]
|
|
83
69
|
pub enum NextWFT {
|
|
84
70
|
ReplayOver,
|
|
85
|
-
WFT(Vec<HistoryEvent
|
|
71
|
+
WFT(Vec<HistoryEvent>, bool),
|
|
86
72
|
NeedFetch,
|
|
87
73
|
}
|
|
88
74
|
|
|
@@ -97,6 +83,7 @@ pub struct HistoryPaginator {
|
|
|
97
83
|
pub(crate) wf_id: String,
|
|
98
84
|
pub(crate) run_id: String,
|
|
99
85
|
pub(crate) previous_wft_started_id: i64,
|
|
86
|
+
pub(crate) wft_started_event_id: i64,
|
|
100
87
|
|
|
101
88
|
#[cfg_attr(feature = "save_wf_inputs", serde(skip))]
|
|
102
89
|
client: Arc<dyn WorkerClient>,
|
|
@@ -147,6 +134,7 @@ impl HistoryPaginator {
|
|
|
147
134
|
let mut paginator = HistoryPaginator::new(
|
|
148
135
|
wft.history,
|
|
149
136
|
wft.previous_started_event_id,
|
|
137
|
+
wft.started_event_id,
|
|
150
138
|
wft.workflow_execution.workflow_id.clone(),
|
|
151
139
|
wft.workflow_execution.run_id.clone(),
|
|
152
140
|
npt,
|
|
@@ -156,7 +144,13 @@ impl HistoryPaginator {
|
|
|
156
144
|
return Err(EMPTY_TASK_ERR.clone());
|
|
157
145
|
}
|
|
158
146
|
let update = if empty_hist {
|
|
159
|
-
HistoryUpdate::from_events(
|
|
147
|
+
HistoryUpdate::from_events(
|
|
148
|
+
[],
|
|
149
|
+
wft.previous_started_event_id,
|
|
150
|
+
wft.started_event_id,
|
|
151
|
+
true,
|
|
152
|
+
)
|
|
153
|
+
.0
|
|
160
154
|
} else {
|
|
161
155
|
paginator.extract_next_update().await?
|
|
162
156
|
};
|
|
@@ -180,6 +174,7 @@ impl HistoryPaginator {
|
|
|
180
174
|
wf_id: req.original_wft.work.execution.workflow_id.clone(),
|
|
181
175
|
run_id: req.original_wft.work.execution.run_id.clone(),
|
|
182
176
|
previous_wft_started_id: req.original_wft.work.update.previous_wft_started_id,
|
|
177
|
+
wft_started_event_id: req.original_wft.work.update.wft_started_id,
|
|
183
178
|
client,
|
|
184
179
|
event_queue: Default::default(),
|
|
185
180
|
next_page_token: NextPageToken::FetchFromStart,
|
|
@@ -194,6 +189,7 @@ impl HistoryPaginator {
|
|
|
194
189
|
fn new(
|
|
195
190
|
initial_history: History,
|
|
196
191
|
previous_wft_started_id: i64,
|
|
192
|
+
wft_started_event_id: i64,
|
|
197
193
|
wf_id: String,
|
|
198
194
|
run_id: String,
|
|
199
195
|
next_page_token: impl Into<NextPageToken>,
|
|
@@ -214,6 +210,7 @@ impl HistoryPaginator {
|
|
|
214
210
|
next_page_token,
|
|
215
211
|
final_events,
|
|
216
212
|
previous_wft_started_id,
|
|
213
|
+
wft_started_event_id,
|
|
217
214
|
}
|
|
218
215
|
}
|
|
219
216
|
|
|
@@ -228,6 +225,7 @@ impl HistoryPaginator {
|
|
|
228
225
|
next_page_token: NextPageToken::FetchFromStart,
|
|
229
226
|
final_events: vec![],
|
|
230
227
|
previous_wft_started_id: -2,
|
|
228
|
+
wft_started_event_id: -2,
|
|
231
229
|
}
|
|
232
230
|
}
|
|
233
231
|
|
|
@@ -242,31 +240,42 @@ impl HistoryPaginator {
|
|
|
242
240
|
/// we have two, or until we are at the end of history.
|
|
243
241
|
pub(crate) async fn extract_next_update(&mut self) -> Result<HistoryUpdate, tonic::Status> {
|
|
244
242
|
loop {
|
|
245
|
-
self.get_next_page().await?;
|
|
243
|
+
let no_next_page = !self.get_next_page().await?;
|
|
246
244
|
let current_events = mem::take(&mut self.event_queue);
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
245
|
+
let seen_enough_events = current_events
|
|
246
|
+
.back()
|
|
247
|
+
.map(|e| e.event_id)
|
|
248
|
+
.unwrap_or_default()
|
|
249
|
+
>= self.wft_started_event_id;
|
|
250
|
+
if current_events.is_empty() || (no_next_page && !seen_enough_events) {
|
|
251
|
+
// If next page fetching happened, and we still ended up with no or insufficient
|
|
252
|
+
// events, something is wrong. We're expecting there to be more events to be able to
|
|
253
|
+
// extract this update, but server isn't giving us any. We have no choice except to
|
|
254
|
+
// give up and evict.
|
|
252
255
|
error!(
|
|
253
256
|
"We expected to be able to fetch more events but server says there are none"
|
|
254
257
|
);
|
|
255
258
|
return Err(EMPTY_FETCH_ERR.clone());
|
|
256
259
|
}
|
|
257
260
|
let first_event_id = current_events.front().unwrap().event_id;
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
let no_more = matches!(self.next_page_token, NextPageToken::Done);
|
|
261
|
-
let (update, extra) =
|
|
262
|
-
|
|
261
|
+
// We only *really* have the last WFT if the events go all the way up to at least the
|
|
262
|
+
// WFT started event id. Otherwise we somehow still have partial history.
|
|
263
|
+
let no_more = matches!(self.next_page_token, NextPageToken::Done) && seen_enough_events;
|
|
264
|
+
let (update, extra) = HistoryUpdate::from_events(
|
|
265
|
+
current_events,
|
|
266
|
+
self.previous_wft_started_id,
|
|
267
|
+
self.wft_started_event_id,
|
|
268
|
+
no_more,
|
|
269
|
+
);
|
|
263
270
|
let extra_eid_same = extra
|
|
264
271
|
.first()
|
|
265
272
|
.map(|e| e.event_id == first_event_id)
|
|
266
273
|
.unwrap_or_default();
|
|
274
|
+
// If there are some events at the end of the fetched events which represent only a
|
|
275
|
+
// portion of a complete WFT, retain them to be used in the next extraction.
|
|
267
276
|
self.event_queue = extra.into();
|
|
268
277
|
if !no_more && extra_eid_same {
|
|
269
|
-
// There was not a meaningful WFT in the whole page. We must fetch more
|
|
278
|
+
// There was not a meaningful WFT in the whole page. We must fetch more.
|
|
270
279
|
continue;
|
|
271
280
|
}
|
|
272
281
|
return Ok(update);
|
|
@@ -278,7 +287,7 @@ impl HistoryPaginator {
|
|
|
278
287
|
async fn get_next_page(&mut self) -> Result<bool, tonic::Status> {
|
|
279
288
|
let history = loop {
|
|
280
289
|
let npt = match mem::replace(&mut self.next_page_token, NextPageToken::Done) {
|
|
281
|
-
// If
|
|
290
|
+
// If the last page token we got was empty, we're done.
|
|
282
291
|
NextPageToken::Done => return Ok(false),
|
|
283
292
|
NextPageToken::FetchFromStart => vec![],
|
|
284
293
|
NextPageToken::Next(v) => v,
|
|
@@ -374,6 +383,23 @@ impl Stream for StreamingHistoryPaginator {
|
|
|
374
383
|
}
|
|
375
384
|
|
|
376
385
|
impl HistoryUpdate {
|
|
386
|
+
/// Sometimes it's useful to take an update out of something without needing to use an option
|
|
387
|
+
/// field. Use this to replace the field with an empty update.
|
|
388
|
+
pub fn dummy() -> Self {
|
|
389
|
+
Self {
|
|
390
|
+
events: vec![],
|
|
391
|
+
previous_wft_started_id: -1,
|
|
392
|
+
wft_started_id: -1,
|
|
393
|
+
has_last_wft: false,
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
pub fn is_real(&self) -> bool {
|
|
397
|
+
self.previous_wft_started_id >= 0
|
|
398
|
+
}
|
|
399
|
+
pub fn first_event_id(&self) -> Option<i64> {
|
|
400
|
+
self.events.get(0).map(|e| e.event_id)
|
|
401
|
+
}
|
|
402
|
+
|
|
377
403
|
/// Create an instance of an update directly from events. If the passed in event iterator has a
|
|
378
404
|
/// partial WFT sequence at the end, all events after the last complete WFT sequence (ending
|
|
379
405
|
/// with WFT started) are returned back to the caller, since the history update only works in
|
|
@@ -381,6 +407,7 @@ impl HistoryUpdate {
|
|
|
381
407
|
pub fn from_events<I: IntoIterator<Item = HistoryEvent>>(
|
|
382
408
|
events: I,
|
|
383
409
|
previous_wft_started_id: i64,
|
|
410
|
+
wft_started_id: i64,
|
|
384
411
|
has_last_wft: bool,
|
|
385
412
|
) -> (Self, Vec<HistoryEvent>)
|
|
386
413
|
where
|
|
@@ -395,6 +422,7 @@ impl HistoryUpdate {
|
|
|
395
422
|
Self {
|
|
396
423
|
events: all_events,
|
|
397
424
|
previous_wft_started_id,
|
|
425
|
+
wft_started_id,
|
|
398
426
|
has_last_wft,
|
|
399
427
|
},
|
|
400
428
|
vec![],
|
|
@@ -404,6 +432,7 @@ impl HistoryUpdate {
|
|
|
404
432
|
Self {
|
|
405
433
|
events: vec![],
|
|
406
434
|
previous_wft_started_id,
|
|
435
|
+
wft_started_id,
|
|
407
436
|
has_last_wft,
|
|
408
437
|
},
|
|
409
438
|
all_events,
|
|
@@ -431,6 +460,7 @@ impl HistoryUpdate {
|
|
|
431
460
|
Self {
|
|
432
461
|
events: all_events,
|
|
433
462
|
previous_wft_started_id,
|
|
463
|
+
wft_started_id,
|
|
434
464
|
has_last_wft,
|
|
435
465
|
},
|
|
436
466
|
remaining_events,
|
|
@@ -444,6 +474,7 @@ impl HistoryUpdate {
|
|
|
444
474
|
pub fn new_from_events<I: IntoIterator<Item = HistoryEvent>>(
|
|
445
475
|
events: I,
|
|
446
476
|
previous_wft_started_id: i64,
|
|
477
|
+
wft_started_id: i64,
|
|
447
478
|
) -> Self
|
|
448
479
|
where
|
|
449
480
|
<I as IntoIterator>::IntoIter: Send + 'static,
|
|
@@ -451,6 +482,7 @@ impl HistoryUpdate {
|
|
|
451
482
|
Self {
|
|
452
483
|
events: events.into_iter().collect(),
|
|
453
484
|
previous_wft_started_id,
|
|
485
|
+
wft_started_id,
|
|
454
486
|
has_last_wft: true,
|
|
455
487
|
}
|
|
456
488
|
}
|
|
@@ -474,7 +506,7 @@ impl HistoryUpdate {
|
|
|
474
506
|
if siz == 0 {
|
|
475
507
|
NextWFT::ReplayOver
|
|
476
508
|
} else {
|
|
477
|
-
|
|
509
|
+
self.build_next_wft(siz)
|
|
478
510
|
}
|
|
479
511
|
} else {
|
|
480
512
|
if siz != 0 {
|
|
@@ -485,12 +517,17 @@ impl HistoryUpdate {
|
|
|
485
517
|
NextWFT::NeedFetch
|
|
486
518
|
}
|
|
487
519
|
}
|
|
488
|
-
NextWFTSeqEndIndex::Complete(next_wft_ix) =>
|
|
489
|
-
NextWFT::WFT(self.events.drain(0..=next_wft_ix).collect())
|
|
490
|
-
}
|
|
520
|
+
NextWFTSeqEndIndex::Complete(next_wft_ix) => self.build_next_wft(next_wft_ix),
|
|
491
521
|
}
|
|
492
522
|
}
|
|
493
523
|
|
|
524
|
+
fn build_next_wft(&mut self, drain_this_much: usize) -> NextWFT {
|
|
525
|
+
NextWFT::WFT(
|
|
526
|
+
self.events.drain(0..=drain_this_much).collect(),
|
|
527
|
+
self.events.is_empty() && self.has_last_wft,
|
|
528
|
+
)
|
|
529
|
+
}
|
|
530
|
+
|
|
494
531
|
/// Lets the caller peek ahead at the next WFT sequence that will be returned by
|
|
495
532
|
/// [take_next_wft_sequence]. Will always return the first available WFT sequence if that has
|
|
496
533
|
/// not been called first. May also return an empty iterator or incomplete sequence if we are at
|
|
@@ -519,6 +556,23 @@ impl HistoryUpdate {
|
|
|
519
556
|
true
|
|
520
557
|
}
|
|
521
558
|
|
|
559
|
+
/// Returns the next WFT completed event attributes, if any, starting at (inclusive) the
|
|
560
|
+
/// `from_id`
|
|
561
|
+
pub fn peek_next_wft_completed(
|
|
562
|
+
&self,
|
|
563
|
+
from_id: i64,
|
|
564
|
+
) -> Option<&WorkflowTaskCompletedEventAttributes> {
|
|
565
|
+
self.events
|
|
566
|
+
.iter()
|
|
567
|
+
.skip_while(|e| e.event_id < from_id)
|
|
568
|
+
.find_map(|e| match &e.attributes {
|
|
569
|
+
Some(history_event::Attributes::WorkflowTaskCompletedEventAttributes(ref a)) => {
|
|
570
|
+
Some(a)
|
|
571
|
+
}
|
|
572
|
+
_ => None,
|
|
573
|
+
})
|
|
574
|
+
}
|
|
575
|
+
|
|
522
576
|
fn starting_index_after_skipping(&self, from_wft_started_id: i64) -> Option<usize> {
|
|
523
577
|
self.events
|
|
524
578
|
.iter()
|
|
@@ -632,7 +686,11 @@ pub mod tests {
|
|
|
632
686
|
|
|
633
687
|
impl From<HistoryInfo> for HistoryUpdate {
|
|
634
688
|
fn from(v: HistoryInfo) -> Self {
|
|
635
|
-
Self::new_from_events(
|
|
689
|
+
Self::new_from_events(
|
|
690
|
+
v.events().to_vec(),
|
|
691
|
+
v.previous_started_event_id(),
|
|
692
|
+
v.workflow_task_started_event_id(),
|
|
693
|
+
)
|
|
636
694
|
}
|
|
637
695
|
}
|
|
638
696
|
|
|
@@ -649,7 +707,7 @@ pub mod tests {
|
|
|
649
707
|
impl NextWFT {
|
|
650
708
|
fn unwrap_events(self) -> Vec<HistoryEvent> {
|
|
651
709
|
match self {
|
|
652
|
-
NextWFT::WFT(e) => e,
|
|
710
|
+
NextWFT::WFT(e, _) => e,
|
|
653
711
|
o => panic!("Must be complete WFT: {o:?}"),
|
|
654
712
|
}
|
|
655
713
|
}
|
|
@@ -726,12 +784,12 @@ pub mod tests {
|
|
|
726
784
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
727
785
|
t.add_full_wf_task();
|
|
728
786
|
t.add_full_wf_task(); // wft started 6
|
|
729
|
-
t.
|
|
787
|
+
t.add_by_type(EventType::TimerStarted);
|
|
730
788
|
t.add_full_wf_task(); // wft started 10
|
|
731
789
|
t.add_full_wf_task();
|
|
732
790
|
t.add_full_wf_task();
|
|
733
791
|
t.add_full_wf_task(); // wft started 19
|
|
734
|
-
t.
|
|
792
|
+
t.add_by_type(EventType::TimerStarted);
|
|
735
793
|
t.add_full_wf_task(); // wft started 23
|
|
736
794
|
t.add_we_signaled("whee", vec![]);
|
|
737
795
|
t.add_full_wf_task();
|
|
@@ -768,7 +826,9 @@ pub mod tests {
|
|
|
768
826
|
}
|
|
769
827
|
|
|
770
828
|
fn paginator_setup(history: TestHistoryBuilder, chunk_size: usize) -> HistoryPaginator {
|
|
771
|
-
let
|
|
829
|
+
let hinfo = history.get_full_history_info().unwrap();
|
|
830
|
+
let wft_started = hinfo.workflow_task_started_event_id();
|
|
831
|
+
let full_hist = hinfo.into_events();
|
|
772
832
|
let initial_hist = full_hist.chunks(chunk_size).next().unwrap().to_vec();
|
|
773
833
|
let mut mock_client = mock_workflow_client();
|
|
774
834
|
|
|
@@ -800,6 +860,7 @@ pub mod tests {
|
|
|
800
860
|
events: initial_hist,
|
|
801
861
|
},
|
|
802
862
|
0,
|
|
863
|
+
wft_started,
|
|
803
864
|
"wfid".to_string(),
|
|
804
865
|
"runid".to_string(),
|
|
805
866
|
vec![1],
|
|
@@ -825,7 +886,7 @@ pub mod tests {
|
|
|
825
886
|
for i in 1..wft_count {
|
|
826
887
|
let seq = {
|
|
827
888
|
match update.take_next_wft_sequence(last_started_id) {
|
|
828
|
-
NextWFT::WFT(seq) => seq,
|
|
889
|
+
NextWFT::WFT(seq, _) => seq,
|
|
829
890
|
NextWFT::NeedFetch => {
|
|
830
891
|
update = paginator.extract_next_update().await.unwrap();
|
|
831
892
|
update
|
|
@@ -867,9 +928,9 @@ pub mod tests {
|
|
|
867
928
|
// Start with two complete normal WFTs
|
|
868
929
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
869
930
|
t.add_full_wf_task(); // wft start - 3
|
|
870
|
-
t.
|
|
931
|
+
t.add_by_type(EventType::TimerStarted);
|
|
871
932
|
t.add_full_wf_task(); // wft start - 7
|
|
872
|
-
t.
|
|
933
|
+
t.add_by_type(EventType::TimerStarted);
|
|
873
934
|
t.add_full_wf_task(); // wft start - 11
|
|
874
935
|
for _ in 1..50 {
|
|
875
936
|
// Add a bunch of heartbeats with no commands, which count as one task
|
|
@@ -887,7 +948,14 @@ pub mod tests {
|
|
|
887
948
|
// The update should contain the first two complete WFTs, ending on the 8th event which
|
|
888
949
|
// is WFT started. The remaining events should be returned. False flags means the creator
|
|
889
950
|
// knows there are more events, so we should return need fetch
|
|
890
|
-
let (mut update, remaining) = HistoryUpdate::from_events(
|
|
951
|
+
let (mut update, remaining) = HistoryUpdate::from_events(
|
|
952
|
+
ends_in_middle_of_seq,
|
|
953
|
+
0,
|
|
954
|
+
t.get_full_history_info()
|
|
955
|
+
.unwrap()
|
|
956
|
+
.workflow_task_started_event_id(),
|
|
957
|
+
false,
|
|
958
|
+
);
|
|
891
959
|
assert_eq!(remaining[0].event_id, 8);
|
|
892
960
|
assert_eq!(remaining.last().unwrap().event_id, 19);
|
|
893
961
|
let seq = update.take_next_wft_sequence(0).unwrap_events();
|
|
@@ -906,7 +974,14 @@ pub mod tests {
|
|
|
906
974
|
let t = three_wfts_then_heartbeats();
|
|
907
975
|
let mut ends_in_middle_of_seq = t.as_history_update().events;
|
|
908
976
|
ends_in_middle_of_seq.truncate(20);
|
|
909
|
-
let (mut update, remaining) = HistoryUpdate::from_events(
|
|
977
|
+
let (mut update, remaining) = HistoryUpdate::from_events(
|
|
978
|
+
ends_in_middle_of_seq,
|
|
979
|
+
0,
|
|
980
|
+
t.get_full_history_info()
|
|
981
|
+
.unwrap()
|
|
982
|
+
.workflow_task_started_event_id(),
|
|
983
|
+
false,
|
|
984
|
+
);
|
|
910
985
|
assert!(remaining.is_empty());
|
|
911
986
|
let seq = update.take_next_wft_sequence(0).unwrap_events();
|
|
912
987
|
assert_eq!(seq.last().unwrap().event_id, 3);
|
|
@@ -930,7 +1005,7 @@ pub mod tests {
|
|
|
930
1005
|
loop {
|
|
931
1006
|
let seq = update.take_next_wft_sequence(last_id);
|
|
932
1007
|
match seq {
|
|
933
|
-
NextWFT::WFT(seq) => {
|
|
1008
|
+
NextWFT::WFT(seq, _) => {
|
|
934
1009
|
last_id = seq.last().unwrap().event_id;
|
|
935
1010
|
}
|
|
936
1011
|
NextWFT::NeedFetch => {
|
|
@@ -965,6 +1040,7 @@ pub mod tests {
|
|
|
965
1040
|
let timer_hist = canned_histories::single_timer("t");
|
|
966
1041
|
let partial_task = timer_hist.get_one_wft(2).unwrap();
|
|
967
1042
|
let prev_started_wft_id = partial_task.previous_started_event_id();
|
|
1043
|
+
let wft_started_id = partial_task.workflow_task_started_event_id();
|
|
968
1044
|
let mut history_from_get: GetWorkflowExecutionHistoryResponse =
|
|
969
1045
|
timer_hist.get_history_info(2).unwrap().into();
|
|
970
1046
|
// Chop off the last event, which is WFT started, which server doesn't return in get
|
|
@@ -978,6 +1054,7 @@ pub mod tests {
|
|
|
978
1054
|
let mut paginator = HistoryPaginator::new(
|
|
979
1055
|
partial_task.into(),
|
|
980
1056
|
prev_started_wft_id,
|
|
1057
|
+
wft_started_id,
|
|
981
1058
|
"wfid".to_string(),
|
|
982
1059
|
"runid".to_string(),
|
|
983
1060
|
// A cache miss means we'll try to fetch from start
|
|
@@ -1026,6 +1103,7 @@ pub mod tests {
|
|
|
1026
1103
|
let timer_hist = canned_histories::single_timer("t");
|
|
1027
1104
|
let partial_task = timer_hist.get_one_wft(2).unwrap();
|
|
1028
1105
|
let prev_started_wft_id = partial_task.previous_started_event_id();
|
|
1106
|
+
let wft_started_id = partial_task.workflow_task_started_event_id();
|
|
1029
1107
|
let mut mock_client = mock_workflow_client();
|
|
1030
1108
|
mock_client
|
|
1031
1109
|
.expect_get_workflow_execution_history()
|
|
@@ -1034,6 +1112,7 @@ pub mod tests {
|
|
|
1034
1112
|
let mut paginator = HistoryPaginator::new(
|
|
1035
1113
|
partial_task.into(),
|
|
1036
1114
|
prev_started_wft_id,
|
|
1115
|
+
wft_started_id,
|
|
1037
1116
|
"wfid".to_string(),
|
|
1038
1117
|
"runid".to_string(),
|
|
1039
1118
|
// A cache miss means we'll try to fetch from start
|
|
@@ -1041,7 +1120,7 @@ pub mod tests {
|
|
|
1041
1120
|
Arc::new(mock_client),
|
|
1042
1121
|
);
|
|
1043
1122
|
let err = paginator.extract_next_update().await.unwrap_err();
|
|
1044
|
-
assert_matches!(err.code(), tonic::Code::
|
|
1123
|
+
assert_matches!(err.code(), tonic::Code::Unknown);
|
|
1045
1124
|
}
|
|
1046
1125
|
|
|
1047
1126
|
#[tokio::test]
|
|
@@ -1049,6 +1128,7 @@ pub mod tests {
|
|
|
1049
1128
|
let timer_hist = canned_histories::single_timer("t");
|
|
1050
1129
|
let partial_task = timer_hist.get_one_wft(2).unwrap();
|
|
1051
1130
|
let prev_started_wft_id = partial_task.previous_started_event_id();
|
|
1131
|
+
let wft_started_id = partial_task.workflow_task_started_event_id();
|
|
1052
1132
|
let full_resp: GetWorkflowExecutionHistoryResponse =
|
|
1053
1133
|
timer_hist.get_full_history_info().unwrap().into();
|
|
1054
1134
|
let mut mock_client = mock_workflow_client();
|
|
@@ -1071,6 +1151,7 @@ pub mod tests {
|
|
|
1071
1151
|
let mut paginator = HistoryPaginator::new(
|
|
1072
1152
|
partial_task.into(),
|
|
1073
1153
|
prev_started_wft_id,
|
|
1154
|
+
wft_started_id,
|
|
1074
1155
|
"wfid".to_string(),
|
|
1075
1156
|
"runid".to_string(),
|
|
1076
1157
|
// A cache miss means we'll try to fetch from start
|