@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
|
@@ -21,19 +21,37 @@ use super::{
|
|
|
21
21
|
workflow_machines::MachineResponse, Cancellable, EventInfo, NewMachineWithCommand,
|
|
22
22
|
OnEventWrapper, WFMachinesAdapter, WFMachinesError,
|
|
23
23
|
};
|
|
24
|
-
use crate::
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
use crate::{
|
|
25
|
+
internal_flags::CoreInternalFlags,
|
|
26
|
+
protosext::HistoryEventExt,
|
|
27
|
+
worker::workflow::{
|
|
28
|
+
machines::{
|
|
29
|
+
upsert_search_attributes_state_machine::MAX_SEARCH_ATTR_PAYLOAD_SIZE, HistEventData,
|
|
30
|
+
},
|
|
31
|
+
InternalFlagsRef,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
use anyhow::Context;
|
|
35
|
+
use rustfsm::{fsm, StateMachine, TransitionResult};
|
|
36
|
+
use std::{
|
|
37
|
+
collections::{BTreeSet, HashMap},
|
|
38
|
+
convert::TryFrom,
|
|
39
|
+
};
|
|
27
40
|
use temporal_sdk_core_protos::{
|
|
28
41
|
constants::PATCH_MARKER_NAME,
|
|
29
|
-
coresdk::common::build_has_change_marker_details,
|
|
42
|
+
coresdk::{common::build_has_change_marker_details, AsJsonPayloadExt},
|
|
30
43
|
temporal::api::{
|
|
31
|
-
command::v1::{
|
|
44
|
+
command::v1::{
|
|
45
|
+
Command, RecordMarkerCommandAttributes, UpsertWorkflowSearchAttributesCommandAttributes,
|
|
46
|
+
},
|
|
47
|
+
common::v1::SearchAttributes,
|
|
32
48
|
enums::v1::CommandType,
|
|
33
49
|
history::v1::HistoryEvent,
|
|
34
50
|
},
|
|
35
51
|
};
|
|
36
52
|
|
|
53
|
+
pub(crate) const VERSION_SEARCH_ATTR_KEY: &str = "TemporalChangeVersion";
|
|
54
|
+
|
|
37
55
|
fsm! {
|
|
38
56
|
pub(super) name PatchMachine;
|
|
39
57
|
command PatchCommand;
|
|
@@ -71,53 +89,90 @@ pub(super) enum PatchCommand {}
|
|
|
71
89
|
/// are guaranteed to return the same value.
|
|
72
90
|
/// `replaying_when_invoked`: If the workflow is replaying when this invocation occurs, this needs
|
|
73
91
|
/// to be set to true.
|
|
74
|
-
pub(super) fn has_change(
|
|
92
|
+
pub(super) fn has_change<'a>(
|
|
75
93
|
patch_id: String,
|
|
76
94
|
replaying_when_invoked: bool,
|
|
77
95
|
deprecated: bool,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
seen_in_peekahead: bool,
|
|
97
|
+
existing_patch_ids: impl Iterator<Item = &'a str>,
|
|
98
|
+
internal_flags: InternalFlagsRef,
|
|
99
|
+
) -> Result<(NewMachineWithCommand, Vec<MachineResponse>), WFMachinesError> {
|
|
100
|
+
let shared_state = SharedState { patch_id };
|
|
101
|
+
let initial_state = if replaying_when_invoked {
|
|
102
|
+
Replaying {}.into()
|
|
103
|
+
} else {
|
|
104
|
+
Executing {}.into()
|
|
105
|
+
};
|
|
106
|
+
let command = Command {
|
|
107
|
+
command_type: CommandType::RecordMarker as i32,
|
|
108
|
+
attributes: Some(
|
|
109
|
+
RecordMarkerCommandAttributes {
|
|
110
|
+
marker_name: PATCH_MARKER_NAME.to_string(),
|
|
111
|
+
details: build_has_change_marker_details(&shared_state.patch_id, deprecated)
|
|
112
|
+
.context("While encoding patch marker details")?,
|
|
113
|
+
header: None,
|
|
114
|
+
failure: None,
|
|
115
|
+
}
|
|
116
|
+
.into(),
|
|
117
|
+
),
|
|
118
|
+
};
|
|
119
|
+
let mut machine = PatchMachine::from_parts(initial_state, shared_state);
|
|
120
|
+
|
|
121
|
+
OnEventWrapper::on_event_mut(&mut machine, PatchMachineEvents::Schedule)
|
|
122
|
+
.expect("Patch machine scheduling doesn't fail");
|
|
123
|
+
|
|
124
|
+
// If we're replaying but this patch isn't in the peekahead, then we wouldn't have
|
|
125
|
+
// upserted either, and thus should not create the machine
|
|
126
|
+
let replaying_and_not_in_history = replaying_when_invoked && !seen_in_peekahead;
|
|
127
|
+
let cannot_use_flag = !internal_flags.borrow_mut().try_use(
|
|
128
|
+
CoreInternalFlags::UpsertSearchAttributeOnPatch,
|
|
129
|
+
!replaying_when_invoked,
|
|
130
|
+
);
|
|
131
|
+
let maybe_upsert_cmd = if replaying_and_not_in_history || cannot_use_flag {
|
|
132
|
+
vec![]
|
|
133
|
+
} else {
|
|
134
|
+
// Produce an upsert SA command for this patch.
|
|
135
|
+
let mut all_ids = BTreeSet::from_iter(existing_patch_ids);
|
|
136
|
+
all_ids.insert(machine.shared_state.patch_id.as_str());
|
|
137
|
+
let serialized = all_ids
|
|
138
|
+
.as_json_payload()
|
|
139
|
+
.context("Could not serialize search attribute value for patch machine")
|
|
140
|
+
.map_err(|e| WFMachinesError::Fatal(e.to_string()))?;
|
|
141
|
+
|
|
142
|
+
if serialized.data.len() >= MAX_SEARCH_ATTR_PAYLOAD_SIZE {
|
|
143
|
+
warn!(
|
|
144
|
+
"Serialized size of {VERSION_SEARCH_ATTR_KEY} search attribute update would \
|
|
145
|
+
exceed the maximum value size. Skipping this upsert. Be aware that your \
|
|
146
|
+
visibility records will not include the following patch: {}",
|
|
147
|
+
machine.shared_state.patch_id
|
|
148
|
+
);
|
|
149
|
+
vec![]
|
|
95
150
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
header: None,
|
|
105
|
-
failure: None,
|
|
151
|
+
let indexed_fields = {
|
|
152
|
+
let mut m = HashMap::new();
|
|
153
|
+
m.insert(VERSION_SEARCH_ATTR_KEY.to_string(), serialized);
|
|
154
|
+
m
|
|
155
|
+
};
|
|
156
|
+
vec![MachineResponse::NewCoreOriginatedCommand(
|
|
157
|
+
UpsertWorkflowSearchAttributesCommandAttributes {
|
|
158
|
+
search_attributes: Some(SearchAttributes { indexed_fields }),
|
|
106
159
|
}
|
|
107
160
|
.into(),
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
state: initial_state,
|
|
112
|
-
shared_state: state,
|
|
113
|
-
};
|
|
114
|
-
OnEventWrapper::on_event_mut(&mut machine, PatchMachineEvents::Schedule)
|
|
115
|
-
.expect("Patch machine scheduling doesn't fail");
|
|
161
|
+
)]
|
|
162
|
+
}
|
|
163
|
+
};
|
|
116
164
|
|
|
117
|
-
|
|
118
|
-
|
|
165
|
+
Ok((
|
|
166
|
+
NewMachineWithCommand {
|
|
167
|
+
command,
|
|
168
|
+
machine: machine.into(),
|
|
169
|
+
},
|
|
170
|
+
maybe_upsert_cmd,
|
|
171
|
+
))
|
|
119
172
|
}
|
|
120
173
|
|
|
174
|
+
impl PatchMachine {}
|
|
175
|
+
|
|
121
176
|
#[derive(Default, Clone)]
|
|
122
177
|
pub(super) struct Executing {}
|
|
123
178
|
|
|
@@ -132,7 +187,7 @@ pub(super) struct MarkerCommandCreated {}
|
|
|
132
187
|
|
|
133
188
|
impl MarkerCommandCreated {
|
|
134
189
|
pub(super) fn on_command_record_marker(self) -> PatchMachineTransition<Notified> {
|
|
135
|
-
TransitionResult::
|
|
190
|
+
TransitionResult::default()
|
|
136
191
|
}
|
|
137
192
|
}
|
|
138
193
|
|
|
@@ -161,7 +216,7 @@ impl From<MarkerCommandCreatedReplaying> for Notified {
|
|
|
161
216
|
impl Notified {
|
|
162
217
|
pub(super) fn on_marker_recorded(
|
|
163
218
|
self,
|
|
164
|
-
dat: SharedState,
|
|
219
|
+
dat: &mut SharedState,
|
|
165
220
|
id: String,
|
|
166
221
|
) -> PatchMachineTransition<MarkerCommandRecorded> {
|
|
167
222
|
if id != dat.patch_id {
|
|
@@ -201,10 +256,11 @@ impl TryFrom<CommandType> for PatchMachineEvents {
|
|
|
201
256
|
}
|
|
202
257
|
}
|
|
203
258
|
|
|
204
|
-
impl TryFrom<
|
|
259
|
+
impl TryFrom<HistEventData> for PatchMachineEvents {
|
|
205
260
|
type Error = WFMachinesError;
|
|
206
261
|
|
|
207
|
-
fn try_from(e:
|
|
262
|
+
fn try_from(e: HistEventData) -> Result<Self, Self::Error> {
|
|
263
|
+
let e = e.event;
|
|
208
264
|
match e.get_patch_marker_details() {
|
|
209
265
|
Some((id, _)) => Ok(Self::MarkerRecorded(id)),
|
|
210
266
|
_ => Err(WFMachinesError::Nondeterminism(format!(
|
|
@@ -217,35 +273,43 @@ impl TryFrom<HistoryEvent> for PatchMachineEvents {
|
|
|
217
273
|
#[cfg(test)]
|
|
218
274
|
mod tests {
|
|
219
275
|
use crate::{
|
|
276
|
+
internal_flags::CoreInternalFlags,
|
|
220
277
|
replay::TestHistoryBuilder,
|
|
221
|
-
worker::workflow::{
|
|
278
|
+
worker::workflow::{
|
|
279
|
+
machines::{patch_state_machine::VERSION_SEARCH_ATTR_KEY, WFMachinesError},
|
|
280
|
+
ManagedWFFunc,
|
|
281
|
+
},
|
|
222
282
|
};
|
|
223
283
|
use rstest::rstest;
|
|
224
|
-
use std::
|
|
284
|
+
use std::{
|
|
285
|
+
collections::{hash_map::RandomState, HashSet, VecDeque},
|
|
286
|
+
time::Duration,
|
|
287
|
+
};
|
|
225
288
|
use temporal_sdk::{ActivityOptions, WfContext, WorkflowFunction};
|
|
226
289
|
use temporal_sdk_core_protos::{
|
|
227
290
|
constants::PATCH_MARKER_NAME,
|
|
228
291
|
coresdk::{
|
|
229
292
|
common::decode_change_marker_details,
|
|
230
293
|
workflow_activation::{workflow_activation_job, NotifyHasPatch, WorkflowActivationJob},
|
|
294
|
+
AsJsonPayloadExt, FromJsonPayloadExt,
|
|
231
295
|
},
|
|
232
296
|
temporal::api::{
|
|
233
297
|
command::v1::{
|
|
234
298
|
command::Attributes, RecordMarkerCommandAttributes,
|
|
235
299
|
ScheduleActivityTaskCommandAttributes,
|
|
300
|
+
UpsertWorkflowSearchAttributesCommandAttributes,
|
|
236
301
|
},
|
|
237
302
|
common::v1::ActivityType,
|
|
238
303
|
enums::v1::{CommandType, EventType},
|
|
239
304
|
history::v1::{
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
TimerFiredEventAttributes,
|
|
305
|
+
ActivityTaskCompletedEventAttributes, ActivityTaskScheduledEventAttributes,
|
|
306
|
+
ActivityTaskStartedEventAttributes, TimerFiredEventAttributes,
|
|
243
307
|
},
|
|
244
308
|
},
|
|
245
309
|
};
|
|
246
310
|
|
|
247
311
|
const MY_PATCH_ID: &str = "test_patch_id";
|
|
248
|
-
#[derive(Eq, PartialEq, Copy, Clone)]
|
|
312
|
+
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
|
249
313
|
enum MarkerType {
|
|
250
314
|
Deprecated,
|
|
251
315
|
NotDeprecated,
|
|
@@ -266,51 +330,65 @@ mod tests {
|
|
|
266
330
|
/// EVENT_TYPE_WORKFLOW_TASK_STARTED
|
|
267
331
|
/// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
|
|
268
332
|
/// EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
|
|
269
|
-
fn patch_marker_single_activity(
|
|
333
|
+
fn patch_marker_single_activity(
|
|
334
|
+
marker_type: MarkerType,
|
|
335
|
+
version: usize,
|
|
336
|
+
replay: bool,
|
|
337
|
+
) -> TestHistoryBuilder {
|
|
270
338
|
let mut t = TestHistoryBuilder::default();
|
|
271
339
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
272
340
|
t.add_full_wf_task();
|
|
341
|
+
t.set_flags_first_wft(
|
|
342
|
+
&[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
|
|
343
|
+
&[],
|
|
344
|
+
);
|
|
273
345
|
match marker_type {
|
|
274
|
-
MarkerType::Deprecated =>
|
|
275
|
-
|
|
346
|
+
MarkerType::Deprecated => {
|
|
347
|
+
t.add_has_change_marker(MY_PATCH_ID, true);
|
|
348
|
+
t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
|
|
349
|
+
}
|
|
350
|
+
MarkerType::NotDeprecated => {
|
|
351
|
+
t.add_has_change_marker(MY_PATCH_ID, false);
|
|
352
|
+
t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
|
|
353
|
+
}
|
|
276
354
|
MarkerType::NoMarker => {}
|
|
277
355
|
};
|
|
278
356
|
|
|
279
|
-
let
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
),
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
)
|
|
313
|
-
);
|
|
357
|
+
let activity_id = if replay {
|
|
358
|
+
match (marker_type, version) {
|
|
359
|
+
(_, 1) => "no_change",
|
|
360
|
+
(MarkerType::NotDeprecated, 2) => "had_change",
|
|
361
|
+
(MarkerType::Deprecated, 2) => "had_change",
|
|
362
|
+
(MarkerType::NoMarker, 2) => "no_change",
|
|
363
|
+
(_, 3) => "had_change",
|
|
364
|
+
(_, 4) => "had_change",
|
|
365
|
+
v => panic!("Nonsense marker / version combo {v:?}"),
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
// If the workflow isn't replaying (we're creating history here for a workflow which
|
|
369
|
+
// wasn't replaying at the time of scheduling the activity, and has done that, and now
|
|
370
|
+
// we're feeding back the history it would have produced) then it always has the change,
|
|
371
|
+
// except in v1.
|
|
372
|
+
if version > 1 {
|
|
373
|
+
"had_change"
|
|
374
|
+
} else {
|
|
375
|
+
"no_change"
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
|
|
380
|
+
activity_id: activity_id.to_string(),
|
|
381
|
+
..Default::default()
|
|
382
|
+
});
|
|
383
|
+
let started_event_id = t.add(ActivityTaskStartedEventAttributes {
|
|
384
|
+
scheduled_event_id,
|
|
385
|
+
..Default::default()
|
|
386
|
+
});
|
|
387
|
+
t.add(ActivityTaskCompletedEventAttributes {
|
|
388
|
+
scheduled_event_id,
|
|
389
|
+
started_event_id,
|
|
390
|
+
..Default::default()
|
|
391
|
+
});
|
|
314
392
|
t.add_full_wf_task();
|
|
315
393
|
t.add_workflow_execution_completed();
|
|
316
394
|
t
|
|
@@ -383,7 +461,7 @@ mod tests {
|
|
|
383
461
|
Ok(().into())
|
|
384
462
|
});
|
|
385
463
|
|
|
386
|
-
let t = patch_marker_single_activity(marker_type);
|
|
464
|
+
let t = patch_marker_single_activity(marker_type, workflow_version, replaying);
|
|
387
465
|
let histinfo = if replaying {
|
|
388
466
|
t.get_full_history_info()
|
|
389
467
|
} else {
|
|
@@ -421,7 +499,7 @@ mod tests {
|
|
|
421
499
|
} else {
|
|
422
500
|
// Feed more history
|
|
423
501
|
wfm.new_history(
|
|
424
|
-
patch_marker_single_activity(marker_type)
|
|
502
|
+
patch_marker_single_activity(marker_type, wf_version, replaying)
|
|
425
503
|
.get_full_history_info()
|
|
426
504
|
.unwrap()
|
|
427
505
|
.into(),
|
|
@@ -446,14 +524,13 @@ mod tests {
|
|
|
446
524
|
wfm.shutdown().await.unwrap();
|
|
447
525
|
}
|
|
448
526
|
|
|
527
|
+
// Note that the not-replaying and no-marker cases don't make sense and hence are absent
|
|
449
528
|
#[rstest]
|
|
450
|
-
#[case::v2_no_marker_old_path(false, MarkerType::NoMarker, 2)]
|
|
451
529
|
#[case::v2_marker_new_path(false, MarkerType::NotDeprecated, 2)]
|
|
452
530
|
#[case::v2_dep_marker_new_path(false, MarkerType::Deprecated, 2)]
|
|
453
531
|
#[case::v2_replay_no_marker_old_path(true, MarkerType::NoMarker, 2)]
|
|
454
532
|
#[case::v2_replay_marker_new_path(true, MarkerType::NotDeprecated, 2)]
|
|
455
533
|
#[case::v2_replay_dep_marker_new_path(true, MarkerType::Deprecated, 2)]
|
|
456
|
-
#[case::v3_no_marker_old_path(false, MarkerType::NoMarker, 3)]
|
|
457
534
|
#[case::v3_marker_new_path(false, MarkerType::NotDeprecated, 3)]
|
|
458
535
|
#[case::v3_dep_marker_new_path(false, MarkerType::Deprecated, 3)]
|
|
459
536
|
#[case::v3_replay_no_marker_old_path(true, MarkerType::NoMarker, 3)]
|
|
@@ -482,17 +559,32 @@ mod tests {
|
|
|
482
559
|
} else {
|
|
483
560
|
assert_eq!(act.jobs.len(), 1);
|
|
484
561
|
}
|
|
485
|
-
let commands = wfm.get_server_commands().commands;
|
|
486
|
-
|
|
562
|
+
let mut commands = VecDeque::from(wfm.get_server_commands().commands);
|
|
563
|
+
let expected_num_cmds = if marker_type == MarkerType::NoMarker {
|
|
564
|
+
2
|
|
565
|
+
} else {
|
|
566
|
+
3
|
|
567
|
+
};
|
|
568
|
+
assert_eq!(commands.len(), expected_num_cmds);
|
|
487
569
|
let dep_flag_expected = wf_version != 2;
|
|
488
570
|
assert_matches!(
|
|
489
|
-
commands
|
|
571
|
+
commands.pop_front().unwrap().attributes.as_ref().unwrap(),
|
|
490
572
|
Attributes::RecordMarkerCommandAttributes(
|
|
491
573
|
RecordMarkerCommandAttributes { marker_name, details,.. })
|
|
492
574
|
|
|
493
575
|
if marker_name == PATCH_MARKER_NAME
|
|
494
576
|
&& decode_change_marker_details(details).unwrap().1 == dep_flag_expected
|
|
495
577
|
);
|
|
578
|
+
if expected_num_cmds == 3 {
|
|
579
|
+
assert_matches!(
|
|
580
|
+
commands.pop_front().unwrap().attributes.as_ref().unwrap(),
|
|
581
|
+
Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
|
|
582
|
+
UpsertWorkflowSearchAttributesCommandAttributes{ search_attributes: Some(attrs) }
|
|
583
|
+
)
|
|
584
|
+
if attrs.indexed_fields.get(VERSION_SEARCH_ATTR_KEY).unwrap()
|
|
585
|
+
== &[MY_PATCH_ID].as_json_payload().unwrap()
|
|
586
|
+
);
|
|
587
|
+
}
|
|
496
588
|
// The only time the "old" timer should fire is in v2, replaying, without a marker.
|
|
497
589
|
let expected_activity_id =
|
|
498
590
|
if replaying && marker_type == MarkerType::NoMarker && wf_version == 2 {
|
|
@@ -501,7 +593,7 @@ mod tests {
|
|
|
501
593
|
"had_change"
|
|
502
594
|
};
|
|
503
595
|
assert_matches!(
|
|
504
|
-
commands
|
|
596
|
+
commands.pop_front().unwrap().attributes.as_ref().unwrap(),
|
|
505
597
|
Attributes::ScheduleActivityTaskCommandAttributes(
|
|
506
598
|
ScheduleActivityTaskCommandAttributes { activity_id, .. }
|
|
507
599
|
)
|
|
@@ -515,7 +607,7 @@ mod tests {
|
|
|
515
607
|
// and the history should have the has-change timer. v3 of course always has the change
|
|
516
608
|
// regardless.
|
|
517
609
|
wfm.new_history(
|
|
518
|
-
patch_marker_single_activity(marker_type)
|
|
610
|
+
patch_marker_single_activity(marker_type, wf_version, replaying)
|
|
519
611
|
.get_full_history_info()
|
|
520
612
|
.unwrap()
|
|
521
613
|
.into(),
|
|
@@ -562,120 +654,73 @@ mod tests {
|
|
|
562
654
|
let mut t = TestHistoryBuilder::default();
|
|
563
655
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
564
656
|
t.add_full_wf_task();
|
|
657
|
+
t.set_flags_first_wft(
|
|
658
|
+
&[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
|
|
659
|
+
&[],
|
|
660
|
+
);
|
|
565
661
|
if have_marker_in_hist {
|
|
566
662
|
t.add_has_change_marker(MY_PATCH_ID, false);
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
activity_id: "1".to_owned(),
|
|
573
|
-
activity_type: Some(ActivityType {
|
|
574
|
-
name: "".to_string(),
|
|
575
|
-
}),
|
|
576
|
-
..Default::default()
|
|
577
|
-
},
|
|
578
|
-
),
|
|
579
|
-
),
|
|
580
|
-
);
|
|
581
|
-
let started_event_id = t.add_get_event_id(
|
|
582
|
-
EventType::ActivityTaskStarted,
|
|
583
|
-
Some(
|
|
584
|
-
history_event::Attributes::ActivityTaskStartedEventAttributes(
|
|
585
|
-
ActivityTaskStartedEventAttributes {
|
|
586
|
-
scheduled_event_id,
|
|
587
|
-
..Default::default()
|
|
588
|
-
},
|
|
589
|
-
),
|
|
590
|
-
),
|
|
591
|
-
);
|
|
592
|
-
t.add(
|
|
593
|
-
EventType::ActivityTaskCompleted,
|
|
594
|
-
history_event::Attributes::ActivityTaskCompletedEventAttributes(
|
|
595
|
-
ActivityTaskCompletedEventAttributes {
|
|
596
|
-
scheduled_event_id,
|
|
597
|
-
started_event_id,
|
|
598
|
-
// TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
|
|
599
|
-
..Default::default()
|
|
600
|
-
},
|
|
601
|
-
),
|
|
602
|
-
);
|
|
603
|
-
t.add_full_wf_task();
|
|
604
|
-
let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
605
|
-
t.add(
|
|
606
|
-
EventType::TimerFired,
|
|
607
|
-
history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
|
|
608
|
-
started_event_id: timer_started_event_id,
|
|
609
|
-
timer_id: "1".to_owned(),
|
|
663
|
+
t.add_upsert_search_attrs_for_patch(&[MY_PATCH_ID.to_string()]);
|
|
664
|
+
let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
|
|
665
|
+
activity_id: "1".to_owned(),
|
|
666
|
+
activity_type: Some(ActivityType {
|
|
667
|
+
name: "".to_string(),
|
|
610
668
|
}),
|
|
611
|
-
|
|
669
|
+
..Default::default()
|
|
670
|
+
});
|
|
671
|
+
let started_event_id = t.add(ActivityTaskStartedEventAttributes {
|
|
672
|
+
scheduled_event_id,
|
|
673
|
+
..Default::default()
|
|
674
|
+
});
|
|
675
|
+
t.add(ActivityTaskCompletedEventAttributes {
|
|
676
|
+
scheduled_event_id,
|
|
677
|
+
started_event_id,
|
|
678
|
+
..Default::default()
|
|
679
|
+
});
|
|
680
|
+
t.add_full_wf_task();
|
|
681
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
682
|
+
t.add(TimerFiredEventAttributes {
|
|
683
|
+
started_event_id: timer_started_event_id,
|
|
684
|
+
timer_id: "1".to_owned(),
|
|
685
|
+
});
|
|
612
686
|
} else {
|
|
613
|
-
let started_event_id = t.
|
|
614
|
-
t.add(
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
timer_id: "1".to_owned(),
|
|
619
|
-
}),
|
|
620
|
-
);
|
|
687
|
+
let started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
688
|
+
t.add(TimerFiredEventAttributes {
|
|
689
|
+
started_event_id,
|
|
690
|
+
timer_id: "1".to_owned(),
|
|
691
|
+
});
|
|
621
692
|
t.add_full_wf_task();
|
|
622
|
-
let timer_started_event_id = t.
|
|
623
|
-
t.add(
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
timer_id: "2".to_owned(),
|
|
628
|
-
}),
|
|
629
|
-
);
|
|
693
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
694
|
+
t.add(TimerFiredEventAttributes {
|
|
695
|
+
started_event_id: timer_started_event_id,
|
|
696
|
+
timer_id: "2".to_owned(),
|
|
697
|
+
});
|
|
630
698
|
}
|
|
631
699
|
t.add_full_wf_task();
|
|
632
700
|
|
|
633
701
|
if have_marker_in_hist {
|
|
634
|
-
let scheduled_event_id = t.
|
|
635
|
-
|
|
636
|
-
Some(
|
|
637
|
-
|
|
638
|
-
ActivityTaskScheduledEventAttributes {
|
|
639
|
-
activity_id: "2".to_string(),
|
|
640
|
-
activity_type: Some(ActivityType {
|
|
641
|
-
name: "".to_string(),
|
|
642
|
-
}),
|
|
643
|
-
..Default::default()
|
|
644
|
-
},
|
|
645
|
-
),
|
|
646
|
-
),
|
|
647
|
-
);
|
|
648
|
-
let started_event_id = t.add_get_event_id(
|
|
649
|
-
EventType::ActivityTaskStarted,
|
|
650
|
-
Some(
|
|
651
|
-
history_event::Attributes::ActivityTaskStartedEventAttributes(
|
|
652
|
-
ActivityTaskStartedEventAttributes {
|
|
653
|
-
scheduled_event_id,
|
|
654
|
-
..Default::default()
|
|
655
|
-
},
|
|
656
|
-
),
|
|
657
|
-
),
|
|
658
|
-
);
|
|
659
|
-
t.add(
|
|
660
|
-
EventType::ActivityTaskCompleted,
|
|
661
|
-
history_event::Attributes::ActivityTaskCompletedEventAttributes(
|
|
662
|
-
ActivityTaskCompletedEventAttributes {
|
|
663
|
-
scheduled_event_id,
|
|
664
|
-
started_event_id,
|
|
665
|
-
// TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
|
|
666
|
-
..Default::default()
|
|
667
|
-
},
|
|
668
|
-
),
|
|
669
|
-
);
|
|
670
|
-
} else {
|
|
671
|
-
let started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
672
|
-
t.add(
|
|
673
|
-
EventType::TimerFired,
|
|
674
|
-
history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
|
|
675
|
-
started_event_id,
|
|
676
|
-
timer_id: "3".to_owned(),
|
|
702
|
+
let scheduled_event_id = t.add(ActivityTaskScheduledEventAttributes {
|
|
703
|
+
activity_id: "2".to_string(),
|
|
704
|
+
activity_type: Some(ActivityType {
|
|
705
|
+
name: "".to_string(),
|
|
677
706
|
}),
|
|
678
|
-
|
|
707
|
+
..Default::default()
|
|
708
|
+
});
|
|
709
|
+
let started_event_id = t.add(ActivityTaskStartedEventAttributes {
|
|
710
|
+
scheduled_event_id,
|
|
711
|
+
..Default::default()
|
|
712
|
+
});
|
|
713
|
+
t.add(ActivityTaskCompletedEventAttributes {
|
|
714
|
+
scheduled_event_id,
|
|
715
|
+
started_event_id,
|
|
716
|
+
..Default::default()
|
|
717
|
+
});
|
|
718
|
+
} else {
|
|
719
|
+
let started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
720
|
+
t.add(TimerFiredEventAttributes {
|
|
721
|
+
started_event_id,
|
|
722
|
+
timer_id: "3".to_owned(),
|
|
723
|
+
});
|
|
679
724
|
}
|
|
680
725
|
t.add_full_wf_task();
|
|
681
726
|
t.add_workflow_execution_completed();
|
|
@@ -704,4 +749,75 @@ mod tests {
|
|
|
704
749
|
|
|
705
750
|
wfm.shutdown().await.unwrap();
|
|
706
751
|
}
|
|
752
|
+
|
|
753
|
+
const SIZE_OVERFLOW_PATCH_AMOUNT: usize = 180;
|
|
754
|
+
#[rstest]
|
|
755
|
+
#[case::happy_path(50)]
|
|
756
|
+
// We start exceeding the 2k size limit at 180 patches with this format
|
|
757
|
+
#[case::size_overflow(SIZE_OVERFLOW_PATCH_AMOUNT)]
|
|
758
|
+
#[tokio::test]
|
|
759
|
+
async fn many_patches_combine_in_search_attrib_update(#[case] num_patches: usize) {
|
|
760
|
+
let mut t = TestHistoryBuilder::default();
|
|
761
|
+
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
762
|
+
t.add_full_wf_task();
|
|
763
|
+
t.set_flags_first_wft(
|
|
764
|
+
&[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
|
|
765
|
+
&[],
|
|
766
|
+
);
|
|
767
|
+
for i in 1..=num_patches {
|
|
768
|
+
let id = format!("patch-{i}");
|
|
769
|
+
t.add_has_change_marker(&id, false);
|
|
770
|
+
if i < SIZE_OVERFLOW_PATCH_AMOUNT {
|
|
771
|
+
t.add_upsert_search_attrs_for_patch(&[id]);
|
|
772
|
+
}
|
|
773
|
+
let timer_started_event_id = t.add_by_type(EventType::TimerStarted);
|
|
774
|
+
t.add(TimerFiredEventAttributes {
|
|
775
|
+
started_event_id: timer_started_event_id,
|
|
776
|
+
timer_id: i.to_string(),
|
|
777
|
+
});
|
|
778
|
+
t.add_full_wf_task();
|
|
779
|
+
}
|
|
780
|
+
t.add_workflow_execution_completed();
|
|
781
|
+
|
|
782
|
+
let mut wfm = ManagedWFFunc::new_from_update(
|
|
783
|
+
t.get_history_info(1).unwrap().into(),
|
|
784
|
+
WorkflowFunction::new(move |ctx: WfContext| async move {
|
|
785
|
+
for i in 1..=num_patches {
|
|
786
|
+
let _dontcare = ctx.patched(&format!("patch-{i}"));
|
|
787
|
+
ctx.timer(ONE_SECOND).await;
|
|
788
|
+
}
|
|
789
|
+
Ok(().into())
|
|
790
|
+
}),
|
|
791
|
+
vec![],
|
|
792
|
+
);
|
|
793
|
+
// Iterate through all activations/responses except the final one with complete workflow
|
|
794
|
+
for i in 2..=num_patches + 1 {
|
|
795
|
+
wfm.get_next_activation().await.unwrap();
|
|
796
|
+
let cmds = wfm.get_server_commands();
|
|
797
|
+
wfm.new_history(t.get_history_info(i).unwrap().into())
|
|
798
|
+
.await
|
|
799
|
+
.unwrap();
|
|
800
|
+
if i > SIZE_OVERFLOW_PATCH_AMOUNT {
|
|
801
|
+
assert_eq!(2, cmds.commands.len());
|
|
802
|
+
assert_matches!(cmds.commands[1].command_type(), CommandType::StartTimer);
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
assert_eq!(3, cmds.commands.len());
|
|
806
|
+
let attrs = assert_matches!(
|
|
807
|
+
cmds.commands[1].attributes.as_ref().unwrap(),
|
|
808
|
+
Attributes::UpsertWorkflowSearchAttributesCommandAttributes(
|
|
809
|
+
UpsertWorkflowSearchAttributesCommandAttributes{ search_attributes: Some(attrs) }
|
|
810
|
+
)
|
|
811
|
+
=> attrs
|
|
812
|
+
);
|
|
813
|
+
let expected_patches: HashSet<String, _> =
|
|
814
|
+
(1..i).map(|i| format!("patch-{i}")).collect();
|
|
815
|
+
let deserialized = HashSet::<String, RandomState>::from_json_payload(
|
|
816
|
+
attrs.indexed_fields.get(VERSION_SEARCH_ATTR_KEY).unwrap(),
|
|
817
|
+
)
|
|
818
|
+
.unwrap();
|
|
819
|
+
assert_eq!(deserialized, expected_patches);
|
|
820
|
+
}
|
|
821
|
+
wfm.shutdown().await.unwrap();
|
|
822
|
+
}
|
|
707
823
|
}
|