@temporalio/core-bridge 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +304 -112
- package/lib/index.d.ts +8 -6
- package/lib/index.js.map +1 -1
- package/package.json +9 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +2 -2
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.buildkite/pipeline.yml +2 -4
- package/sdk-core/.cargo/config.toml +5 -2
- package/sdk-core/.github/workflows/heavy.yml +29 -0
- package/sdk-core/Cargo.toml +1 -1
- package/sdk-core/README.md +20 -10
- package/sdk-core/client/src/lib.rs +215 -39
- package/sdk-core/client/src/metrics.rs +17 -8
- package/sdk-core/client/src/raw.rs +4 -4
- package/sdk-core/client/src/retry.rs +32 -20
- package/sdk-core/core/Cargo.toml +25 -12
- package/sdk-core/core/src/abstractions/take_cell.rs +28 -0
- package/sdk-core/core/src/abstractions.rs +204 -14
- package/sdk-core/core/src/core_tests/activity_tasks.rs +143 -50
- package/sdk-core/core/src/core_tests/child_workflows.rs +6 -5
- package/sdk-core/core/src/core_tests/determinism.rs +165 -2
- package/sdk-core/core/src/core_tests/local_activities.rs +431 -43
- package/sdk-core/core/src/core_tests/queries.rs +34 -16
- package/sdk-core/core/src/core_tests/workers.rs +8 -5
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +588 -55
- package/sdk-core/core/src/ephemeral_server/mod.rs +113 -12
- package/sdk-core/core/src/internal_flags.rs +155 -0
- package/sdk-core/core/src/lib.rs +16 -9
- package/sdk-core/core/src/protosext/mod.rs +1 -1
- package/sdk-core/core/src/replay/mod.rs +16 -27
- package/sdk-core/core/src/telemetry/log_export.rs +1 -1
- package/sdk-core/core/src/telemetry/metrics.rs +69 -35
- package/sdk-core/core/src/telemetry/mod.rs +60 -21
- package/sdk-core/core/src/telemetry/prometheus_server.rs +19 -13
- package/sdk-core/core/src/test_help/mod.rs +73 -14
- 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 +379 -129
- package/sdk-core/core/src/worker/activities.rs +350 -175
- 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 +183 -64
- package/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- package/sdk-core/core/src/worker/workflow/history_update.rs +916 -277
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +216 -183
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +9 -12
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +160 -87
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +13 -14
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +7 -9
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +14 -17
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +242 -110
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +27 -19
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +9 -11
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +321 -206
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +13 -18
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +20 -29
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +257 -51
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +6 -17
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +310 -150
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +17 -20
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +31 -15
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1052 -380
- package/sdk-core/core/src/worker/workflow/mod.rs +598 -390
- package/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +137 -0
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +469 -718
- package/sdk-core/core-api/Cargo.toml +2 -1
- package/sdk-core/core-api/src/errors.rs +1 -34
- package/sdk-core/core-api/src/lib.rs +19 -9
- package/sdk-core/core-api/src/telemetry.rs +4 -6
- package/sdk-core/core-api/src/worker.rs +19 -1
- package/sdk-core/etc/deps.svg +115 -140
- package/sdk-core/etc/regen-depgraph.sh +5 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +86 -61
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +29 -71
- package/sdk-core/histories/ends_empty_wft_complete.bin +0 -0
- package/sdk-core/histories/evict_while_la_running_no_interference-16_history.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 +6 -6
- package/sdk-core/protos/api_upstream/build/go.mod +7 -0
- package/sdk-core/protos/api_upstream/build/go.sum +5 -0
- package/sdk-core/protos/api_upstream/build/tools.go +29 -0
- package/sdk-core/protos/api_upstream/go.mod +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +9 -2
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +7 -26
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +13 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +3 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +3 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +8 -8
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +25 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +24 -19
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +49 -26
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +5 -2
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/protocol/v1/message.proto +57 -0
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +71 -6
- package/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -28
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -4
- 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 +67 -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/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +2 -2
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +2 -2
- package/sdk-core/sdk/Cargo.toml +5 -4
- package/sdk-core/sdk/src/lib.rs +108 -26
- 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 +16 -15
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- package/sdk-core/sdk-core-protos/build.rs +36 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +138 -106
- package/sdk-core/sdk-core-protos/src/history_info.rs +10 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +272 -87
- package/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +106 -296
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +82 -23
- package/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- package/sdk-core/test-utils/src/workflows.rs +29 -0
- package/sdk-core/tests/fuzzy_workflow.rs +130 -0
- package/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +10 -5
- package/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- package/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
- package/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- package/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +161 -72
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- 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 +6 -2
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +94 -200
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +34 -28
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +76 -7
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +7 -8
- package/sdk-core/tests/integ_tests/workflow_tests.rs +13 -14
- package/sdk-core/tests/main.rs +3 -13
- package/sdk-core/tests/runner.rs +75 -36
- package/sdk-core/tests/wf_input_replay.rs +32 -0
- package/src/conversions.rs +14 -8
- package/src/runtime.rs +9 -8
- package/ts/index.ts +8 -6
- package/sdk-core/bridge-ffi/Cargo.toml +0 -24
- package/sdk-core/bridge-ffi/LICENSE.txt +0 -23
- package/sdk-core/bridge-ffi/build.rs +0 -25
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -224
- package/sdk-core/bridge-ffi/src/lib.rs +0 -746
- package/sdk-core/bridge-ffi/src/wrappers.rs +0 -221
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +0 -210
- package/sdk-core/sdk/src/conversions.rs +0 -8
|
@@ -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,15 +256,15 @@ 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!(
|
|
211
|
-
"Change machine cannot handle this event: {}"
|
|
212
|
-
e
|
|
267
|
+
"Change machine cannot handle this event: {e}"
|
|
213
268
|
))),
|
|
214
269
|
}
|
|
215
270
|
}
|
|
@@ -218,35 +273,43 @@ impl TryFrom<HistoryEvent> for PatchMachineEvents {
|
|
|
218
273
|
#[cfg(test)]
|
|
219
274
|
mod tests {
|
|
220
275
|
use crate::{
|
|
276
|
+
internal_flags::CoreInternalFlags,
|
|
221
277
|
replay::TestHistoryBuilder,
|
|
222
|
-
worker::workflow::{
|
|
278
|
+
worker::workflow::{
|
|
279
|
+
machines::{patch_state_machine::VERSION_SEARCH_ATTR_KEY, WFMachinesError},
|
|
280
|
+
ManagedWFFunc,
|
|
281
|
+
},
|
|
223
282
|
};
|
|
224
283
|
use rstest::rstest;
|
|
225
|
-
use std::
|
|
284
|
+
use std::{
|
|
285
|
+
collections::{hash_map::RandomState, HashSet, VecDeque},
|
|
286
|
+
time::Duration,
|
|
287
|
+
};
|
|
226
288
|
use temporal_sdk::{ActivityOptions, WfContext, WorkflowFunction};
|
|
227
289
|
use temporal_sdk_core_protos::{
|
|
228
290
|
constants::PATCH_MARKER_NAME,
|
|
229
291
|
coresdk::{
|
|
230
292
|
common::decode_change_marker_details,
|
|
231
293
|
workflow_activation::{workflow_activation_job, NotifyHasPatch, WorkflowActivationJob},
|
|
294
|
+
AsJsonPayloadExt, FromJsonPayloadExt,
|
|
232
295
|
},
|
|
233
296
|
temporal::api::{
|
|
234
297
|
command::v1::{
|
|
235
298
|
command::Attributes, RecordMarkerCommandAttributes,
|
|
236
299
|
ScheduleActivityTaskCommandAttributes,
|
|
300
|
+
UpsertWorkflowSearchAttributesCommandAttributes,
|
|
237
301
|
},
|
|
238
302
|
common::v1::ActivityType,
|
|
239
303
|
enums::v1::{CommandType, EventType},
|
|
240
304
|
history::v1::{
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
TimerFiredEventAttributes,
|
|
305
|
+
ActivityTaskCompletedEventAttributes, ActivityTaskScheduledEventAttributes,
|
|
306
|
+
ActivityTaskStartedEventAttributes, TimerFiredEventAttributes,
|
|
244
307
|
},
|
|
245
308
|
},
|
|
246
309
|
};
|
|
247
310
|
|
|
248
311
|
const MY_PATCH_ID: &str = "test_patch_id";
|
|
249
|
-
#[derive(Eq, PartialEq, Copy, Clone)]
|
|
312
|
+
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
|
250
313
|
enum MarkerType {
|
|
251
314
|
Deprecated,
|
|
252
315
|
NotDeprecated,
|
|
@@ -267,51 +330,65 @@ mod tests {
|
|
|
267
330
|
/// EVENT_TYPE_WORKFLOW_TASK_STARTED
|
|
268
331
|
/// EVENT_TYPE_WORKFLOW_TASK_COMPLETED
|
|
269
332
|
/// EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
|
|
270
|
-
fn patch_marker_single_activity(
|
|
333
|
+
fn patch_marker_single_activity(
|
|
334
|
+
marker_type: MarkerType,
|
|
335
|
+
version: usize,
|
|
336
|
+
replay: bool,
|
|
337
|
+
) -> TestHistoryBuilder {
|
|
271
338
|
let mut t = TestHistoryBuilder::default();
|
|
272
339
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
273
340
|
t.add_full_wf_task();
|
|
341
|
+
t.set_flags_first_wft(
|
|
342
|
+
&[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
|
|
343
|
+
&[],
|
|
344
|
+
);
|
|
274
345
|
match marker_type {
|
|
275
|
-
MarkerType::Deprecated =>
|
|
276
|
-
|
|
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
|
+
}
|
|
277
354
|
MarkerType::NoMarker => {}
|
|
278
355
|
};
|
|
279
356
|
|
|
280
|
-
let
|
|
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
|
-
)
|
|
314
|
-
);
|
|
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
|
+
});
|
|
315
392
|
t.add_full_wf_task();
|
|
316
393
|
t.add_workflow_execution_completed();
|
|
317
394
|
t
|
|
@@ -384,7 +461,7 @@ mod tests {
|
|
|
384
461
|
Ok(().into())
|
|
385
462
|
});
|
|
386
463
|
|
|
387
|
-
let t = patch_marker_single_activity(marker_type);
|
|
464
|
+
let t = patch_marker_single_activity(marker_type, workflow_version, replaying);
|
|
388
465
|
let histinfo = if replaying {
|
|
389
466
|
t.get_full_history_info()
|
|
390
467
|
} else {
|
|
@@ -422,7 +499,7 @@ mod tests {
|
|
|
422
499
|
} else {
|
|
423
500
|
// Feed more history
|
|
424
501
|
wfm.new_history(
|
|
425
|
-
patch_marker_single_activity(marker_type)
|
|
502
|
+
patch_marker_single_activity(marker_type, wf_version, replaying)
|
|
426
503
|
.get_full_history_info()
|
|
427
504
|
.unwrap()
|
|
428
505
|
.into(),
|
|
@@ -447,14 +524,13 @@ mod tests {
|
|
|
447
524
|
wfm.shutdown().await.unwrap();
|
|
448
525
|
}
|
|
449
526
|
|
|
527
|
+
// Note that the not-replaying and no-marker cases don't make sense and hence are absent
|
|
450
528
|
#[rstest]
|
|
451
|
-
#[case::v2_no_marker_old_path(false, MarkerType::NoMarker, 2)]
|
|
452
529
|
#[case::v2_marker_new_path(false, MarkerType::NotDeprecated, 2)]
|
|
453
530
|
#[case::v2_dep_marker_new_path(false, MarkerType::Deprecated, 2)]
|
|
454
531
|
#[case::v2_replay_no_marker_old_path(true, MarkerType::NoMarker, 2)]
|
|
455
532
|
#[case::v2_replay_marker_new_path(true, MarkerType::NotDeprecated, 2)]
|
|
456
533
|
#[case::v2_replay_dep_marker_new_path(true, MarkerType::Deprecated, 2)]
|
|
457
|
-
#[case::v3_no_marker_old_path(false, MarkerType::NoMarker, 3)]
|
|
458
534
|
#[case::v3_marker_new_path(false, MarkerType::NotDeprecated, 3)]
|
|
459
535
|
#[case::v3_dep_marker_new_path(false, MarkerType::Deprecated, 3)]
|
|
460
536
|
#[case::v3_replay_no_marker_old_path(true, MarkerType::NoMarker, 3)]
|
|
@@ -483,17 +559,32 @@ mod tests {
|
|
|
483
559
|
} else {
|
|
484
560
|
assert_eq!(act.jobs.len(), 1);
|
|
485
561
|
}
|
|
486
|
-
let commands = wfm.get_server_commands().commands;
|
|
487
|
-
|
|
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);
|
|
488
569
|
let dep_flag_expected = wf_version != 2;
|
|
489
570
|
assert_matches!(
|
|
490
|
-
commands
|
|
571
|
+
commands.pop_front().unwrap().attributes.as_ref().unwrap(),
|
|
491
572
|
Attributes::RecordMarkerCommandAttributes(
|
|
492
573
|
RecordMarkerCommandAttributes { marker_name, details,.. })
|
|
493
574
|
|
|
494
575
|
if marker_name == PATCH_MARKER_NAME
|
|
495
576
|
&& decode_change_marker_details(details).unwrap().1 == dep_flag_expected
|
|
496
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
|
+
}
|
|
497
588
|
// The only time the "old" timer should fire is in v2, replaying, without a marker.
|
|
498
589
|
let expected_activity_id =
|
|
499
590
|
if replaying && marker_type == MarkerType::NoMarker && wf_version == 2 {
|
|
@@ -502,7 +593,7 @@ mod tests {
|
|
|
502
593
|
"had_change"
|
|
503
594
|
};
|
|
504
595
|
assert_matches!(
|
|
505
|
-
commands
|
|
596
|
+
commands.pop_front().unwrap().attributes.as_ref().unwrap(),
|
|
506
597
|
Attributes::ScheduleActivityTaskCommandAttributes(
|
|
507
598
|
ScheduleActivityTaskCommandAttributes { activity_id, .. }
|
|
508
599
|
)
|
|
@@ -516,7 +607,7 @@ mod tests {
|
|
|
516
607
|
// and the history should have the has-change timer. v3 of course always has the change
|
|
517
608
|
// regardless.
|
|
518
609
|
wfm.new_history(
|
|
519
|
-
patch_marker_single_activity(marker_type)
|
|
610
|
+
patch_marker_single_activity(marker_type, wf_version, replaying)
|
|
520
611
|
.get_full_history_info()
|
|
521
612
|
.unwrap()
|
|
522
613
|
.into(),
|
|
@@ -563,120 +654,73 @@ mod tests {
|
|
|
563
654
|
let mut t = TestHistoryBuilder::default();
|
|
564
655
|
t.add_by_type(EventType::WorkflowExecutionStarted);
|
|
565
656
|
t.add_full_wf_task();
|
|
657
|
+
t.set_flags_first_wft(
|
|
658
|
+
&[CoreInternalFlags::UpsertSearchAttributeOnPatch as u32],
|
|
659
|
+
&[],
|
|
660
|
+
);
|
|
566
661
|
if have_marker_in_hist {
|
|
567
662
|
t.add_has_change_marker(MY_PATCH_ID, false);
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
activity_id: "1".to_owned(),
|
|
574
|
-
activity_type: Some(ActivityType {
|
|
575
|
-
name: "".to_string(),
|
|
576
|
-
}),
|
|
577
|
-
..Default::default()
|
|
578
|
-
},
|
|
579
|
-
),
|
|
580
|
-
),
|
|
581
|
-
);
|
|
582
|
-
let started_event_id = t.add_get_event_id(
|
|
583
|
-
EventType::ActivityTaskStarted,
|
|
584
|
-
Some(
|
|
585
|
-
history_event::Attributes::ActivityTaskStartedEventAttributes(
|
|
586
|
-
ActivityTaskStartedEventAttributes {
|
|
587
|
-
scheduled_event_id,
|
|
588
|
-
..Default::default()
|
|
589
|
-
},
|
|
590
|
-
),
|
|
591
|
-
),
|
|
592
|
-
);
|
|
593
|
-
t.add(
|
|
594
|
-
EventType::ActivityTaskCompleted,
|
|
595
|
-
history_event::Attributes::ActivityTaskCompletedEventAttributes(
|
|
596
|
-
ActivityTaskCompletedEventAttributes {
|
|
597
|
-
scheduled_event_id,
|
|
598
|
-
started_event_id,
|
|
599
|
-
// TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
|
|
600
|
-
..Default::default()
|
|
601
|
-
},
|
|
602
|
-
),
|
|
603
|
-
);
|
|
604
|
-
t.add_full_wf_task();
|
|
605
|
-
let timer_started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
606
|
-
t.add(
|
|
607
|
-
EventType::TimerFired,
|
|
608
|
-
history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
|
|
609
|
-
started_event_id: timer_started_event_id,
|
|
610
|
-
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(),
|
|
611
668
|
}),
|
|
612
|
-
|
|
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
|
+
});
|
|
613
686
|
} else {
|
|
614
|
-
let started_event_id = t.
|
|
615
|
-
t.add(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
timer_id: "1".to_owned(),
|
|
620
|
-
}),
|
|
621
|
-
);
|
|
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
|
+
});
|
|
622
692
|
t.add_full_wf_task();
|
|
623
|
-
let timer_started_event_id = t.
|
|
624
|
-
t.add(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
timer_id: "2".to_owned(),
|
|
629
|
-
}),
|
|
630
|
-
);
|
|
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
|
+
});
|
|
631
698
|
}
|
|
632
699
|
t.add_full_wf_task();
|
|
633
700
|
|
|
634
701
|
if have_marker_in_hist {
|
|
635
|
-
let scheduled_event_id = t.
|
|
636
|
-
|
|
637
|
-
Some(
|
|
638
|
-
|
|
639
|
-
ActivityTaskScheduledEventAttributes {
|
|
640
|
-
activity_id: "2".to_string(),
|
|
641
|
-
activity_type: Some(ActivityType {
|
|
642
|
-
name: "".to_string(),
|
|
643
|
-
}),
|
|
644
|
-
..Default::default()
|
|
645
|
-
},
|
|
646
|
-
),
|
|
647
|
-
),
|
|
648
|
-
);
|
|
649
|
-
let started_event_id = t.add_get_event_id(
|
|
650
|
-
EventType::ActivityTaskStarted,
|
|
651
|
-
Some(
|
|
652
|
-
history_event::Attributes::ActivityTaskStartedEventAttributes(
|
|
653
|
-
ActivityTaskStartedEventAttributes {
|
|
654
|
-
scheduled_event_id,
|
|
655
|
-
..Default::default()
|
|
656
|
-
},
|
|
657
|
-
),
|
|
658
|
-
),
|
|
659
|
-
);
|
|
660
|
-
t.add(
|
|
661
|
-
EventType::ActivityTaskCompleted,
|
|
662
|
-
history_event::Attributes::ActivityTaskCompletedEventAttributes(
|
|
663
|
-
ActivityTaskCompletedEventAttributes {
|
|
664
|
-
scheduled_event_id,
|
|
665
|
-
started_event_id,
|
|
666
|
-
// TODO result: Some(Payloads { payloads: vec![Payload{ metadata: Default::default(), data: vec![] }] }),
|
|
667
|
-
..Default::default()
|
|
668
|
-
},
|
|
669
|
-
),
|
|
670
|
-
);
|
|
671
|
-
} else {
|
|
672
|
-
let started_event_id = t.add_get_event_id(EventType::TimerStarted, None);
|
|
673
|
-
t.add(
|
|
674
|
-
EventType::TimerFired,
|
|
675
|
-
history_event::Attributes::TimerFiredEventAttributes(TimerFiredEventAttributes {
|
|
676
|
-
started_event_id,
|
|
677
|
-
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(),
|
|
678
706
|
}),
|
|
679
|
-
|
|
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
|
+
});
|
|
680
724
|
}
|
|
681
725
|
t.add_full_wf_task();
|
|
682
726
|
t.add_workflow_execution_completed();
|
|
@@ -705,4 +749,75 @@ mod tests {
|
|
|
705
749
|
|
|
706
750
|
wfm.shutdown().await.unwrap();
|
|
707
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
|
+
}
|
|
708
823
|
}
|