@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
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
mod local_acts;
|
|
2
2
|
|
|
3
|
-
pub(crate) use temporal_sdk_core_api::errors::WFMachinesError;
|
|
4
|
-
|
|
5
3
|
use super::{
|
|
6
|
-
|
|
4
|
+
cancel_external_state_machine::new_external_cancel,
|
|
7
5
|
cancel_workflow_state_machine::cancel_workflow,
|
|
8
|
-
child_workflow_state_machine::new_child_workflow,
|
|
9
6
|
complete_workflow_state_machine::complete_workflow,
|
|
10
7
|
continue_as_new_workflow_state_machine::continue_as_new,
|
|
11
8
|
fail_workflow_state_machine::fail_workflow, local_activity_state_machine::new_local_activity,
|
|
@@ -16,13 +13,23 @@ use super::{
|
|
|
16
13
|
TemporalStateMachine,
|
|
17
14
|
};
|
|
18
15
|
use crate::{
|
|
16
|
+
internal_flags::InternalFlags,
|
|
19
17
|
protosext::{HistoryEventExt, ValidScheduleLA},
|
|
20
18
|
telemetry::{metrics::MetricsContext, VecDisplayer},
|
|
21
19
|
worker::{
|
|
22
20
|
workflow::{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
history_update::NextWFT,
|
|
22
|
+
machines::{
|
|
23
|
+
activity_state_machine::ActivityMachine,
|
|
24
|
+
child_workflow_state_machine::ChildWorkflowMachine,
|
|
25
|
+
modify_workflow_properties_state_machine::modify_workflow_properties,
|
|
26
|
+
patch_state_machine::VERSION_SEARCH_ATTR_KEY,
|
|
27
|
+
upsert_search_attributes_state_machine::upsert_search_attrs_internal,
|
|
28
|
+
HistEventData,
|
|
29
|
+
},
|
|
30
|
+
CommandID, DrivenWorkflow, HistoryUpdate, InternalFlagsRef, LocalResolution,
|
|
31
|
+
OutgoingJob, RunBasics, WFCommand, WFMachinesError, WorkflowFetcher,
|
|
32
|
+
WorkflowStartedInfo,
|
|
26
33
|
},
|
|
27
34
|
ExecutingLAId, LocalActRequest, LocalActivityExecutionResult, LocalActivityResolution,
|
|
28
35
|
},
|
|
@@ -31,9 +38,11 @@ use siphasher::sip::SipHasher13;
|
|
|
31
38
|
use slotmap::{SlotMap, SparseSecondaryMap};
|
|
32
39
|
use std::{
|
|
33
40
|
borrow::{Borrow, BorrowMut},
|
|
41
|
+
cell::RefCell,
|
|
34
42
|
collections::{HashMap, VecDeque},
|
|
35
43
|
convert::TryInto,
|
|
36
44
|
hash::{Hash, Hasher},
|
|
45
|
+
rc::Rc,
|
|
37
46
|
time::{Duration, Instant, SystemTime},
|
|
38
47
|
};
|
|
39
48
|
use temporal_sdk_core_protos::{
|
|
@@ -50,7 +59,8 @@ use temporal_sdk_core_protos::{
|
|
|
50
59
|
temporal::api::{
|
|
51
60
|
command::v1::{command::Attributes as ProtoCmdAttrs, Command as ProtoCommand},
|
|
52
61
|
enums::v1::EventType,
|
|
53
|
-
history::v1::{history_event, HistoryEvent},
|
|
62
|
+
history::v1::{history_event, history_event::Attributes, HistoryEvent},
|
|
63
|
+
sdk::v1::WorkflowTaskCompletedMetadata,
|
|
54
64
|
},
|
|
55
65
|
};
|
|
56
66
|
|
|
@@ -95,6 +105,9 @@ pub(crate) struct WorkflowMachines {
|
|
|
95
105
|
/// The current workflow time if it has been established. This may differ from the WFT start
|
|
96
106
|
/// time since local activities may advance the clock
|
|
97
107
|
current_wf_time: Option<SystemTime>,
|
|
108
|
+
/// The internal flags which have been seen so far during this run's execution and thus are
|
|
109
|
+
/// usable during replay.
|
|
110
|
+
observed_internal_flags: InternalFlagsRef,
|
|
98
111
|
|
|
99
112
|
all_machines: SlotMap<MachineKey, Machines>,
|
|
100
113
|
/// If a machine key is in this map, that machine was created internally by core, not as a
|
|
@@ -133,7 +146,7 @@ pub(crate) struct WorkflowMachines {
|
|
|
133
146
|
}
|
|
134
147
|
|
|
135
148
|
#[derive(Debug, derive_more::Display)]
|
|
136
|
-
#[display(fmt = "Cmd&Machine({})"
|
|
149
|
+
#[display(fmt = "Cmd&Machine({command})")]
|
|
137
150
|
struct CommandAndMachine {
|
|
138
151
|
command: MachineAssociatedCommand,
|
|
139
152
|
machine: MachineKey,
|
|
@@ -142,7 +155,7 @@ struct CommandAndMachine {
|
|
|
142
155
|
#[derive(Debug, derive_more::Display)]
|
|
143
156
|
enum MachineAssociatedCommand {
|
|
144
157
|
Real(Box<ProtoCommand>),
|
|
145
|
-
#[display(fmt = "FakeLocalActivityMarker({})"
|
|
158
|
+
#[display(fmt = "FakeLocalActivityMarker({_0})")]
|
|
146
159
|
FakeLocalActivityMarker(u32),
|
|
147
160
|
}
|
|
148
161
|
|
|
@@ -156,7 +169,7 @@ struct ChangeInfo {
|
|
|
156
169
|
#[must_use]
|
|
157
170
|
#[allow(clippy::large_enum_variant)]
|
|
158
171
|
pub(super) enum MachineResponse {
|
|
159
|
-
#[display(fmt = "PushWFJob({})"
|
|
172
|
+
#[display(fmt = "PushWFJob({_0})")]
|
|
160
173
|
PushWFJob(OutgoingJob),
|
|
161
174
|
|
|
162
175
|
/// Pushes a new command into the list that will be sent to server once we respond with the
|
|
@@ -165,31 +178,31 @@ pub(super) enum MachineResponse {
|
|
|
165
178
|
/// The machine requests the creation of another *different* machine. This acts as if lang
|
|
166
179
|
/// had replied to the activation with a command, but we use a special set of IDs to avoid
|
|
167
180
|
/// collisions.
|
|
168
|
-
#[display(fmt = "NewCoreOriginatedCommand({:?})"
|
|
181
|
+
#[display(fmt = "NewCoreOriginatedCommand({_0:?})")]
|
|
169
182
|
NewCoreOriginatedCommand(ProtoCmdAttrs),
|
|
170
|
-
#[display(fmt = "IssueFakeLocalActivityMarker({})"
|
|
183
|
+
#[display(fmt = "IssueFakeLocalActivityMarker({_0})")]
|
|
171
184
|
IssueFakeLocalActivityMarker(u32),
|
|
172
185
|
#[display(fmt = "TriggerWFTaskStarted")]
|
|
173
186
|
TriggerWFTaskStarted {
|
|
174
187
|
task_started_event_id: i64,
|
|
175
188
|
time: SystemTime,
|
|
176
189
|
},
|
|
177
|
-
#[display(fmt = "UpdateRunIdOnWorkflowReset({})"
|
|
190
|
+
#[display(fmt = "UpdateRunIdOnWorkflowReset({run_id})")]
|
|
178
191
|
UpdateRunIdOnWorkflowReset { run_id: String },
|
|
179
192
|
|
|
180
193
|
/// Queue a local activity to be processed by the worker
|
|
181
194
|
#[display(fmt = "QueueLocalActivity")]
|
|
182
195
|
QueueLocalActivity(ValidScheduleLA),
|
|
183
196
|
/// Request cancellation of an executing local activity
|
|
184
|
-
#[display(fmt = "RequestCancelLocalActivity({})"
|
|
197
|
+
#[display(fmt = "RequestCancelLocalActivity({_0})")]
|
|
185
198
|
RequestCancelLocalActivity(u32),
|
|
186
199
|
/// Indicates we are abandoning the indicated LA, so we can remove it from "outstanding" LAs
|
|
187
200
|
/// and we will not try to WFT heartbeat because of it.
|
|
188
|
-
#[display(fmt = "AbandonLocalActivity({:?})"
|
|
201
|
+
#[display(fmt = "AbandonLocalActivity({_0:?})")]
|
|
189
202
|
AbandonLocalActivity(u32),
|
|
190
203
|
|
|
191
204
|
/// Set the workflow time to the provided time
|
|
192
|
-
#[display(fmt = "UpdateWFTime({:?})"
|
|
205
|
+
#[display(fmt = "UpdateWFTime({_0:?})")]
|
|
193
206
|
UpdateWFTime(Option<SystemTime>),
|
|
194
207
|
}
|
|
195
208
|
|
|
@@ -203,25 +216,22 @@ where
|
|
|
203
216
|
}
|
|
204
217
|
|
|
205
218
|
impl WorkflowMachines {
|
|
206
|
-
pub(crate) fn new(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
metrics: MetricsContext,
|
|
214
|
-
) -> Self {
|
|
215
|
-
let replaying = history.previous_started_event_id > 0;
|
|
219
|
+
pub(crate) fn new(basics: RunBasics, driven_wf: DrivenWorkflow) -> Self {
|
|
220
|
+
let replaying = basics.history.previous_wft_started_id > 0;
|
|
221
|
+
let mut observed_internal_flags = InternalFlags::new(basics.capabilities);
|
|
222
|
+
// Peek ahead to determine used patches in the first WFT.
|
|
223
|
+
if let Some(attrs) = basics.history.peek_next_wft_completed(0) {
|
|
224
|
+
observed_internal_flags.add_from_complete(attrs);
|
|
225
|
+
};
|
|
216
226
|
Self {
|
|
217
|
-
last_history_from_server: history,
|
|
218
|
-
namespace,
|
|
219
|
-
workflow_id,
|
|
220
|
-
workflow_type,
|
|
221
|
-
run_id,
|
|
227
|
+
last_history_from_server: basics.history,
|
|
228
|
+
namespace: basics.namespace,
|
|
229
|
+
workflow_id: basics.workflow_id,
|
|
230
|
+
workflow_type: basics.workflow_type,
|
|
231
|
+
run_id: basics.run_id,
|
|
222
232
|
drive_me: driven_wf,
|
|
223
233
|
replaying,
|
|
224
|
-
metrics,
|
|
234
|
+
metrics: basics.metrics,
|
|
225
235
|
// In an ideal world one could say ..Default::default() here and it'd still work.
|
|
226
236
|
current_started_event_id: 0,
|
|
227
237
|
next_started_event_id: 0,
|
|
@@ -230,6 +240,7 @@ impl WorkflowMachines {
|
|
|
230
240
|
workflow_end_time: None,
|
|
231
241
|
wft_start_time: None,
|
|
232
242
|
current_wf_time: None,
|
|
243
|
+
observed_internal_flags: Rc::new(RefCell::new(observed_internal_flags)),
|
|
233
244
|
all_machines: Default::default(),
|
|
234
245
|
machine_is_core_created: Default::default(),
|
|
235
246
|
machines_by_event_id: Default::default(),
|
|
@@ -255,10 +266,10 @@ impl WorkflowMachines {
|
|
|
255
266
|
.and_then(|(st, et)| et.duration_since(st).ok())
|
|
256
267
|
}
|
|
257
268
|
|
|
258
|
-
pub(crate)
|
|
269
|
+
pub(crate) fn new_history_from_server(&mut self, update: HistoryUpdate) -> Result<()> {
|
|
259
270
|
self.last_history_from_server = update;
|
|
260
|
-
self.replaying = self.last_history_from_server.
|
|
261
|
-
self.apply_next_wft_from_history()
|
|
271
|
+
self.replaying = self.last_history_from_server.previous_wft_started_id > 0;
|
|
272
|
+
self.apply_next_wft_from_history()?;
|
|
262
273
|
Ok(())
|
|
263
274
|
}
|
|
264
275
|
|
|
@@ -290,9 +301,8 @@ impl WorkflowMachines {
|
|
|
290
301
|
self.process_machine_responses(mk, resps)?;
|
|
291
302
|
} else {
|
|
292
303
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
293
|
-
"Command matching activity with seq num {} existed but was not a \
|
|
294
|
-
local activity!"
|
|
295
|
-
seq
|
|
304
|
+
"Command matching activity with seq num {seq} existed but was not a \
|
|
305
|
+
local activity!"
|
|
296
306
|
)));
|
|
297
307
|
}
|
|
298
308
|
self.local_activity_data.done_executing(seq);
|
|
@@ -350,6 +360,12 @@ impl WorkflowMachines {
|
|
|
350
360
|
run_id: self.run_id.clone(),
|
|
351
361
|
history_length: self.last_processed_event as u32,
|
|
352
362
|
jobs,
|
|
363
|
+
available_internal_flags: (*self.observed_internal_flags)
|
|
364
|
+
.borrow()
|
|
365
|
+
.all_lang()
|
|
366
|
+
.iter()
|
|
367
|
+
.copied()
|
|
368
|
+
.collect(),
|
|
353
369
|
}
|
|
354
370
|
}
|
|
355
371
|
|
|
@@ -364,10 +380,22 @@ impl WorkflowMachines {
|
|
|
364
380
|
.any(|v| v.is_la_resolution)
|
|
365
381
|
}
|
|
366
382
|
|
|
383
|
+
pub(crate) fn get_metadata_for_wft_complete(&self) -> WorkflowTaskCompletedMetadata {
|
|
384
|
+
(*self.observed_internal_flags)
|
|
385
|
+
.borrow_mut()
|
|
386
|
+
.gather_for_wft_complete()
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
pub(crate) fn add_lang_used_flags(&self, flags: Vec<u32>) {
|
|
390
|
+
(*self.observed_internal_flags)
|
|
391
|
+
.borrow_mut()
|
|
392
|
+
.add_lang_used(flags);
|
|
393
|
+
}
|
|
394
|
+
|
|
367
395
|
/// Iterate the state machines, which consists of grabbing any pending outgoing commands from
|
|
368
396
|
/// the workflow code, handling them, and preparing them to be sent off to the server.
|
|
369
|
-
pub(crate)
|
|
370
|
-
let results = self.drive_me.fetch_workflow_iteration_output()
|
|
397
|
+
pub(crate) fn iterate_machines(&mut self) -> Result<()> {
|
|
398
|
+
let results = self.drive_me.fetch_workflow_iteration_output();
|
|
371
399
|
self.handle_driven_results(results)?;
|
|
372
400
|
self.prepare_commands()?;
|
|
373
401
|
if self.workflow_is_finished() {
|
|
@@ -378,27 +406,60 @@ impl WorkflowMachines {
|
|
|
378
406
|
Ok(())
|
|
379
407
|
}
|
|
380
408
|
|
|
409
|
+
/// Returns true if machines are ready to apply the next WFT sequence, false if events will need
|
|
410
|
+
/// to be fetched in order to create a complete update with the entire next WFT sequence.
|
|
411
|
+
pub(crate) fn ready_to_apply_next_wft(&self) -> bool {
|
|
412
|
+
self.last_history_from_server
|
|
413
|
+
.can_take_next_wft_sequence(self.current_started_event_id)
|
|
414
|
+
}
|
|
415
|
+
|
|
381
416
|
/// Apply the next (unapplied) entire workflow task from history to these machines. Will replay
|
|
382
|
-
/// any events that need to be replayed until caught up to the newest WFT.
|
|
383
|
-
|
|
384
|
-
pub(crate) async fn apply_next_wft_from_history(&mut self) -> Result<usize> {
|
|
417
|
+
/// any events that need to be replayed until caught up to the newest WFT.
|
|
418
|
+
pub(crate) fn apply_next_wft_from_history(&mut self) -> Result<usize> {
|
|
385
419
|
// If we have already seen the terminal event for the entire workflow in a previous WFT,
|
|
386
420
|
// then we don't need to do anything here, and in fact we need to avoid re-applying the
|
|
387
421
|
// final WFT.
|
|
388
422
|
if self.have_seen_terminal_event {
|
|
423
|
+
// Replay clearly counts as done now, since we return here and never do anything else.
|
|
424
|
+
self.replaying = false;
|
|
389
425
|
return Ok(0);
|
|
390
426
|
}
|
|
391
427
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
let
|
|
428
|
+
fn update_internal_flags(me: &mut WorkflowMachines) {
|
|
429
|
+
// Update observed patches with any that were used in the task
|
|
430
|
+
if let Some(next_complete) = me
|
|
395
431
|
.last_history_from_server
|
|
396
|
-
.
|
|
397
|
-
|
|
398
|
-
.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
432
|
+
.peek_next_wft_completed(me.last_processed_event)
|
|
433
|
+
{
|
|
434
|
+
(*me.observed_internal_flags)
|
|
435
|
+
.borrow_mut()
|
|
436
|
+
.add_from_complete(next_complete);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// We update the internal flags before applying the current task (peeking to the completion
|
|
441
|
+
// of this task), and also at the end (peeking to the completion of the task that lang is
|
|
442
|
+
// about to generate commands for, and for which we will want those flags active).
|
|
443
|
+
update_internal_flags(self);
|
|
444
|
+
|
|
445
|
+
let last_handled_wft_started_id = self.current_started_event_id;
|
|
446
|
+
let (events, has_final_event) = match self
|
|
447
|
+
.last_history_from_server
|
|
448
|
+
.take_next_wft_sequence(last_handled_wft_started_id)
|
|
449
|
+
{
|
|
450
|
+
NextWFT::ReplayOver => (vec![], true),
|
|
451
|
+
NextWFT::WFT(mut evts, has_final_event) => {
|
|
452
|
+
// Do not re-process events we have already processed
|
|
453
|
+
evts.retain(|e| e.event_id > self.last_processed_event);
|
|
454
|
+
(evts, has_final_event)
|
|
455
|
+
}
|
|
456
|
+
NextWFT::NeedFetch => {
|
|
457
|
+
return Err(WFMachinesError::Fatal(
|
|
458
|
+
"Need to fetch history events to continue applying workflow task, but this \
|
|
459
|
+
should be prevented ahead of time! This is a Core SDK bug."
|
|
460
|
+
.to_string(),
|
|
461
|
+
));
|
|
462
|
+
}
|
|
402
463
|
};
|
|
403
464
|
let num_events_to_process = events.len();
|
|
404
465
|
|
|
@@ -414,6 +475,8 @@ impl WorkflowMachines {
|
|
|
414
475
|
}
|
|
415
476
|
}
|
|
416
477
|
|
|
478
|
+
let mut saw_completed = false;
|
|
479
|
+
let mut do_handle_event = true;
|
|
417
480
|
let mut history = events.into_iter().peekable();
|
|
418
481
|
while let Some(event) = history.next() {
|
|
419
482
|
if event.event_id != self.last_processed_event + 1 {
|
|
@@ -424,17 +487,52 @@ impl WorkflowMachines {
|
|
|
424
487
|
}
|
|
425
488
|
let next_event = history.peek();
|
|
426
489
|
let eid = event.event_id;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
490
|
+
|
|
491
|
+
// This definition of replaying here is that we are no longer replaying as soon as we
|
|
492
|
+
// see new events that have never been seen or produced by the SDK.
|
|
493
|
+
//
|
|
494
|
+
// Specifically, replay ends once we have seen the last command-event which was produced
|
|
495
|
+
// as a result of the last completed WFT. Thus, replay would be false for things like
|
|
496
|
+
// signals which were received and after the last completion, and thus generated the
|
|
497
|
+
// current WFT being handled.
|
|
498
|
+
if self.replaying && has_final_event && saw_completed && !event.is_command_event() {
|
|
499
|
+
// Replay is finished
|
|
500
|
+
self.replaying = false;
|
|
501
|
+
}
|
|
502
|
+
if event.event_type() == EventType::WorkflowTaskCompleted {
|
|
503
|
+
saw_completed = true;
|
|
432
504
|
}
|
|
505
|
+
|
|
506
|
+
if do_handle_event {
|
|
507
|
+
let eho = self.handle_event(
|
|
508
|
+
HistEventData {
|
|
509
|
+
event,
|
|
510
|
+
replaying: self.replaying,
|
|
511
|
+
current_task_is_last_in_history: has_final_event,
|
|
512
|
+
},
|
|
513
|
+
next_event,
|
|
514
|
+
)?;
|
|
515
|
+
if matches!(
|
|
516
|
+
eho,
|
|
517
|
+
EventHandlingOutcome::SkipEvent {
|
|
518
|
+
skip_next_event: true
|
|
519
|
+
}
|
|
520
|
+
) {
|
|
521
|
+
do_handle_event = false;
|
|
522
|
+
}
|
|
523
|
+
} else {
|
|
524
|
+
do_handle_event = true;
|
|
525
|
+
}
|
|
526
|
+
self.last_processed_event = eid;
|
|
433
527
|
}
|
|
434
528
|
|
|
435
529
|
// Scan through to the next WFT, searching for any patch / la markers, so that we can
|
|
436
530
|
// pre-resolve them.
|
|
437
|
-
|
|
531
|
+
let mut wake_las = vec![];
|
|
532
|
+
for e in self
|
|
533
|
+
.last_history_from_server
|
|
534
|
+
.peek_next_wft_sequence(last_handled_wft_started_id)
|
|
535
|
+
{
|
|
438
536
|
if let Some((patch_id, _)) = e.get_patch_marker_details() {
|
|
439
537
|
self.encountered_change_markers.insert(
|
|
440
538
|
patch_id.clone(),
|
|
@@ -448,10 +546,35 @@ impl WorkflowMachines {
|
|
|
448
546
|
.into(),
|
|
449
547
|
);
|
|
450
548
|
} else if e.is_local_activity_marker() {
|
|
451
|
-
|
|
549
|
+
if let Some(la_dat) = e.clone().into_local_activity_marker_details() {
|
|
550
|
+
if let Ok(mk) =
|
|
551
|
+
self.get_machine_key(CommandID::LocalActivity(la_dat.marker_dat.seq))
|
|
552
|
+
{
|
|
553
|
+
wake_las.push((mk, la_dat));
|
|
554
|
+
} else {
|
|
555
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
556
|
+
}
|
|
557
|
+
} else {
|
|
558
|
+
return Err(WFMachinesError::Fatal(format!(
|
|
559
|
+
"Local activity marker was unparsable: {e:?}"
|
|
560
|
+
)));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
for (mk, la_dat) in wake_las {
|
|
565
|
+
let mach = self.machine_mut(mk);
|
|
566
|
+
if let Machines::LocalActivityMachine(ref mut lam) = *mach {
|
|
567
|
+
if lam.will_accept_resolve_marker() {
|
|
568
|
+
let resps = lam.try_resolve_with_dat(la_dat.into())?;
|
|
569
|
+
self.process_machine_responses(mk, resps)?;
|
|
570
|
+
} else {
|
|
571
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
572
|
+
}
|
|
452
573
|
}
|
|
453
574
|
}
|
|
454
575
|
|
|
576
|
+
update_internal_flags(self);
|
|
577
|
+
|
|
455
578
|
if !self.replaying {
|
|
456
579
|
self.metrics.wf_task_replay_latency(replay_start.elapsed());
|
|
457
580
|
}
|
|
@@ -459,16 +582,20 @@ impl WorkflowMachines {
|
|
|
459
582
|
Ok(num_events_to_process)
|
|
460
583
|
}
|
|
461
584
|
|
|
462
|
-
/// Handle a single event from the workflow history.
|
|
463
|
-
/// is the last event in the history.
|
|
585
|
+
/// Handle a single event from the workflow history.
|
|
464
586
|
///
|
|
465
587
|
/// This function will attempt to apply the event to the workflow state machines. If there is
|
|
466
588
|
/// not a matching machine for the event, a nondeterminism error is returned. Otherwise, the
|
|
467
589
|
/// event is applied to the machine, which may also return a nondeterminism error if the machine
|
|
468
590
|
/// does not match the expected type. A fatal error may be returned if the machine is in an
|
|
469
591
|
/// invalid state.
|
|
470
|
-
#[instrument(skip(self,
|
|
471
|
-
fn handle_event(
|
|
592
|
+
#[instrument(skip(self, event_dat), fields(event=%event_dat))]
|
|
593
|
+
fn handle_event(
|
|
594
|
+
&mut self,
|
|
595
|
+
event_dat: HistEventData,
|
|
596
|
+
next_event: Option<&HistoryEvent>,
|
|
597
|
+
) -> Result<EventHandlingOutcome> {
|
|
598
|
+
let event = &event_dat.event;
|
|
472
599
|
if event.is_final_wf_execution_event() {
|
|
473
600
|
self.have_seen_terminal_event = true;
|
|
474
601
|
}
|
|
@@ -476,39 +603,33 @@ impl WorkflowMachines {
|
|
|
476
603
|
event.event_type(),
|
|
477
604
|
EventType::WorkflowExecutionTerminated | EventType::WorkflowExecutionTimedOut
|
|
478
605
|
) {
|
|
479
|
-
|
|
606
|
+
let are_more_events =
|
|
607
|
+
next_event.is_some() || !event_dat.current_task_is_last_in_history;
|
|
608
|
+
return if are_more_events {
|
|
480
609
|
Err(WFMachinesError::Fatal(
|
|
481
610
|
"Machines were fed a history which has an event after workflow execution was \
|
|
482
611
|
terminated!"
|
|
483
612
|
.to_string(),
|
|
484
613
|
))
|
|
485
614
|
} else {
|
|
486
|
-
Ok(
|
|
615
|
+
Ok(EventHandlingOutcome::Normal)
|
|
487
616
|
};
|
|
488
617
|
}
|
|
489
|
-
if self.replaying
|
|
490
|
-
&& self.current_started_event_id
|
|
491
|
-
>= self.last_history_from_server.previous_started_event_id
|
|
492
|
-
&& event.event_type() != EventType::WorkflowTaskCompleted
|
|
493
|
-
{
|
|
494
|
-
// Replay is finished
|
|
495
|
-
self.replaying = false;
|
|
496
|
-
}
|
|
497
618
|
if event.event_type() == EventType::Unspecified || event.attributes.is_none() {
|
|
498
619
|
return if !event.worker_may_ignore {
|
|
499
620
|
Err(WFMachinesError::Fatal(format!(
|
|
500
|
-
"Event type is unspecified! This history is invalid. Event detail: {:?}"
|
|
501
|
-
event
|
|
621
|
+
"Event type is unspecified! This history is invalid. Event detail: {event:?}"
|
|
502
622
|
)))
|
|
503
623
|
} else {
|
|
504
624
|
debug!("Event is ignorable");
|
|
505
|
-
Ok(
|
|
625
|
+
Ok(EventHandlingOutcome::SkipEvent {
|
|
626
|
+
skip_next_event: false,
|
|
627
|
+
})
|
|
506
628
|
};
|
|
507
629
|
}
|
|
508
630
|
|
|
509
631
|
if event.is_command_event() {
|
|
510
|
-
self.handle_command_event(
|
|
511
|
-
return Ok(());
|
|
632
|
+
return self.handle_command_event(event_dat, next_event);
|
|
512
633
|
}
|
|
513
634
|
|
|
514
635
|
if let Some(initial_cmd_id) = event.get_initial_command_event_id() {
|
|
@@ -517,7 +638,7 @@ impl WorkflowMachines {
|
|
|
517
638
|
let maybe_machine = self.machines_by_event_id.remove(&initial_cmd_id);
|
|
518
639
|
match maybe_machine {
|
|
519
640
|
Some(sm) => {
|
|
520
|
-
self.submachine_handle_event(sm,
|
|
641
|
+
self.submachine_handle_event(sm, event_dat)?;
|
|
521
642
|
// Restore machine if not in it's final state
|
|
522
643
|
if !self.machine(sm).is_final_state() {
|
|
523
644
|
self.machines_by_event_id.insert(initial_cmd_id, sm);
|
|
@@ -526,16 +647,15 @@ impl WorkflowMachines {
|
|
|
526
647
|
None => {
|
|
527
648
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
528
649
|
"During event handling, this event had an initial command ID but we \
|
|
529
|
-
could not find a matching command for it: {:?}"
|
|
530
|
-
event
|
|
650
|
+
could not find a matching command for it: {event:?}"
|
|
531
651
|
)));
|
|
532
652
|
}
|
|
533
653
|
}
|
|
534
654
|
} else {
|
|
535
|
-
self.handle_non_stateful_event(
|
|
655
|
+
self.handle_non_stateful_event(event_dat)?;
|
|
536
656
|
}
|
|
537
657
|
|
|
538
|
-
Ok(
|
|
658
|
+
Ok(EventHandlingOutcome::Normal)
|
|
539
659
|
}
|
|
540
660
|
|
|
541
661
|
/// A command event is an event which is generated from a command emitted as a result of
|
|
@@ -547,23 +667,28 @@ impl WorkflowMachines {
|
|
|
547
667
|
/// The handling consists of verifying that the next command in the commands queue is associated
|
|
548
668
|
/// with a state machine, which is then notified about the event and the command is removed from
|
|
549
669
|
/// the commands queue.
|
|
550
|
-
fn handle_command_event(
|
|
670
|
+
fn handle_command_event(
|
|
671
|
+
&mut self,
|
|
672
|
+
event_dat: HistEventData,
|
|
673
|
+
next_event: Option<&HistoryEvent>,
|
|
674
|
+
) -> Result<EventHandlingOutcome> {
|
|
675
|
+
let event = &event_dat.event;
|
|
676
|
+
|
|
551
677
|
if event.is_local_activity_marker() {
|
|
552
678
|
let deets = event.extract_local_activity_marker_data().ok_or_else(|| {
|
|
553
|
-
WFMachinesError::Fatal(format!("Local activity marker was unparsable: {:?}"
|
|
679
|
+
WFMachinesError::Fatal(format!("Local activity marker was unparsable: {event:?}"))
|
|
554
680
|
})?;
|
|
555
681
|
let cmdid = CommandID::LocalActivity(deets.seq);
|
|
556
682
|
let mkey = self.get_machine_key(cmdid)?;
|
|
557
683
|
if let Machines::LocalActivityMachine(lam) = self.machine(mkey) {
|
|
558
684
|
if lam.marker_should_get_special_handling()? {
|
|
559
|
-
self.submachine_handle_event(mkey,
|
|
560
|
-
return Ok(
|
|
685
|
+
self.submachine_handle_event(mkey, event_dat)?;
|
|
686
|
+
return Ok(EventHandlingOutcome::Normal);
|
|
561
687
|
}
|
|
562
688
|
} else {
|
|
563
689
|
return Err(WFMachinesError::Fatal(format!(
|
|
564
690
|
"Encountered local activity marker but the associated machine was of the \
|
|
565
|
-
wrong type! {:?}"
|
|
566
|
-
event
|
|
691
|
+
wrong type! {event:?}"
|
|
567
692
|
)));
|
|
568
693
|
}
|
|
569
694
|
}
|
|
@@ -573,13 +698,13 @@ impl WorkflowMachines {
|
|
|
573
698
|
let consumed_cmd = loop {
|
|
574
699
|
if let Some(peek_machine) = self.commands.front() {
|
|
575
700
|
let mach = self.machine(peek_machine.machine);
|
|
576
|
-
match change_marker_handling(
|
|
577
|
-
|
|
578
|
-
ChangeMarkerOutcome::SkipCommand => {
|
|
701
|
+
match change_marker_handling(event, mach, next_event)? {
|
|
702
|
+
EventHandlingOutcome::SkipCommand => {
|
|
579
703
|
self.commands.pop_front();
|
|
580
704
|
continue;
|
|
581
705
|
}
|
|
582
|
-
|
|
706
|
+
eho @ EventHandlingOutcome::SkipEvent { .. } => return Ok(eho),
|
|
707
|
+
EventHandlingOutcome::Normal => {}
|
|
583
708
|
}
|
|
584
709
|
}
|
|
585
710
|
|
|
@@ -588,8 +713,7 @@ impl WorkflowMachines {
|
|
|
588
713
|
c
|
|
589
714
|
} else {
|
|
590
715
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
591
|
-
"No command scheduled for event {}"
|
|
592
|
-
event
|
|
716
|
+
"No command scheduled for event {event}"
|
|
593
717
|
)));
|
|
594
718
|
};
|
|
595
719
|
|
|
@@ -599,7 +723,7 @@ impl WorkflowMachines {
|
|
|
599
723
|
|
|
600
724
|
if !canceled_before_sent {
|
|
601
725
|
// Feed the machine the event
|
|
602
|
-
self.submachine_handle_event(command.machine,
|
|
726
|
+
self.submachine_handle_event(command.machine, event_dat)?;
|
|
603
727
|
break command;
|
|
604
728
|
}
|
|
605
729
|
};
|
|
@@ -609,26 +733,22 @@ impl WorkflowMachines {
|
|
|
609
733
|
.insert(event_id, consumed_cmd.machine);
|
|
610
734
|
}
|
|
611
735
|
|
|
612
|
-
Ok(
|
|
736
|
+
Ok(EventHandlingOutcome::Normal)
|
|
613
737
|
}
|
|
614
738
|
|
|
615
|
-
fn handle_non_stateful_event(
|
|
616
|
-
&mut self,
|
|
617
|
-
event: HistoryEvent,
|
|
618
|
-
has_next_event: bool,
|
|
619
|
-
) -> Result<()> {
|
|
739
|
+
fn handle_non_stateful_event(&mut self, event_dat: HistEventData) -> Result<()> {
|
|
620
740
|
trace!(
|
|
621
|
-
event = %event,
|
|
741
|
+
event = %event_dat.event,
|
|
622
742
|
"handling non-stateful event"
|
|
623
743
|
);
|
|
624
|
-
let event_id = event.event_id;
|
|
625
|
-
match EventType::from_i32(event.event_type) {
|
|
744
|
+
let event_id = event_dat.event.event_id;
|
|
745
|
+
match EventType::from_i32(event_dat.event.event_type) {
|
|
626
746
|
Some(EventType::WorkflowExecutionStarted) => {
|
|
627
747
|
if let Some(history_event::Attributes::WorkflowExecutionStartedEventAttributes(
|
|
628
748
|
attrs,
|
|
629
|
-
)) = event.attributes
|
|
749
|
+
)) = event_dat.event.attributes
|
|
630
750
|
{
|
|
631
|
-
if let Some(st) = event.event_time.clone() {
|
|
751
|
+
if let Some(st) = event_dat.event.event_time.clone() {
|
|
632
752
|
let as_systime: SystemTime = st.try_into()?;
|
|
633
753
|
self.workflow_start_time = Some(as_systime);
|
|
634
754
|
// Set the workflow time to be the event time of the first event, so that
|
|
@@ -640,26 +760,25 @@ impl WorkflowMachines {
|
|
|
640
760
|
self.drive_me.start(
|
|
641
761
|
self.workflow_id.clone(),
|
|
642
762
|
str_to_randomness_seed(&attrs.original_execution_run_id),
|
|
643
|
-
event.event_time.unwrap_or_default(),
|
|
763
|
+
event_dat.event.event_time.unwrap_or_default(),
|
|
644
764
|
attrs,
|
|
645
765
|
);
|
|
646
766
|
} else {
|
|
647
767
|
return Err(WFMachinesError::Fatal(format!(
|
|
648
|
-
"WorkflowExecutionStarted event did not have appropriate attributes: {}"
|
|
649
|
-
event
|
|
768
|
+
"WorkflowExecutionStarted event did not have appropriate attributes: {event_dat}"
|
|
650
769
|
)));
|
|
651
770
|
}
|
|
652
771
|
}
|
|
653
772
|
Some(EventType::WorkflowTaskScheduled) => {
|
|
654
773
|
let wf_task_sm = WorkflowTaskMachine::new(self.next_started_event_id);
|
|
655
774
|
let key = self.all_machines.insert(wf_task_sm.into());
|
|
656
|
-
self.submachine_handle_event(key,
|
|
775
|
+
self.submachine_handle_event(key, event_dat)?;
|
|
657
776
|
self.machines_by_event_id.insert(event_id, key);
|
|
658
777
|
}
|
|
659
778
|
Some(EventType::WorkflowExecutionSignaled) => {
|
|
660
779
|
if let Some(history_event::Attributes::WorkflowExecutionSignaledEventAttributes(
|
|
661
780
|
attrs,
|
|
662
|
-
)) = event.attributes
|
|
781
|
+
)) = event_dat.event.attributes
|
|
663
782
|
{
|
|
664
783
|
self.drive_me
|
|
665
784
|
.send_job(workflow_activation::SignalWorkflow::from(attrs).into());
|
|
@@ -672,7 +791,7 @@ impl WorkflowMachines {
|
|
|
672
791
|
history_event::Attributes::WorkflowExecutionCancelRequestedEventAttributes(
|
|
673
792
|
attrs,
|
|
674
793
|
),
|
|
675
|
-
) = event.attributes
|
|
794
|
+
) = event_dat.event.attributes
|
|
676
795
|
{
|
|
677
796
|
self.drive_me
|
|
678
797
|
.send_job(workflow_activation::CancelWorkflow::from(attrs).into());
|
|
@@ -682,8 +801,7 @@ impl WorkflowMachines {
|
|
|
682
801
|
}
|
|
683
802
|
_ => {
|
|
684
803
|
return Err(WFMachinesError::Fatal(format!(
|
|
685
|
-
"The event is not a non-stateful event, but we tried to handle it as one: {}"
|
|
686
|
-
event
|
|
804
|
+
"The event is not a non-stateful event, but we tried to handle it as one: {event_dat}"
|
|
687
805
|
)));
|
|
688
806
|
}
|
|
689
807
|
}
|
|
@@ -700,13 +818,8 @@ impl WorkflowMachines {
|
|
|
700
818
|
|
|
701
819
|
/// Wrapper for calling [TemporalStateMachine::handle_event] which appropriately takes action
|
|
702
820
|
/// on the returned machine responses
|
|
703
|
-
fn submachine_handle_event(
|
|
704
|
-
|
|
705
|
-
sm: MachineKey,
|
|
706
|
-
event: HistoryEvent,
|
|
707
|
-
has_next_event: bool,
|
|
708
|
-
) -> Result<()> {
|
|
709
|
-
let machine_responses = self.machine_mut(sm).handle_event(event, has_next_event)?;
|
|
821
|
+
fn submachine_handle_event(&mut self, sm: MachineKey, event: HistEventData) -> Result<()> {
|
|
822
|
+
let machine_responses = self.machine_mut(sm).handle_event(event)?;
|
|
710
823
|
self.process_machine_responses(sm, machine_responses)?;
|
|
711
824
|
Ok(())
|
|
712
825
|
}
|
|
@@ -756,7 +869,7 @@ impl WorkflowMachines {
|
|
|
756
869
|
) -> Result<()> {
|
|
757
870
|
let sm = self.machine(smk);
|
|
758
871
|
if !machine_responses.is_empty() {
|
|
759
|
-
|
|
872
|
+
trace!(responses = %machine_responses.display(), machine_name = %sm.name(),
|
|
760
873
|
"Machine produced responses");
|
|
761
874
|
}
|
|
762
875
|
self.process_machine_resps_impl(smk, machine_responses)
|
|
@@ -809,10 +922,18 @@ impl WorkflowMachines {
|
|
|
809
922
|
CommandIdKind::CoreInternal,
|
|
810
923
|
);
|
|
811
924
|
}
|
|
925
|
+
ProtoCmdAttrs::UpsertWorkflowSearchAttributesCommandAttributes(attrs) => {
|
|
926
|
+
self.add_cmd_to_wf_task(
|
|
927
|
+
upsert_search_attrs_internal(
|
|
928
|
+
attrs,
|
|
929
|
+
self.observed_internal_flags.clone(),
|
|
930
|
+
),
|
|
931
|
+
CommandIdKind::NeverResolves,
|
|
932
|
+
);
|
|
933
|
+
}
|
|
812
934
|
c => {
|
|
813
935
|
return Err(WFMachinesError::Fatal(format!(
|
|
814
|
-
"A machine requested to create a new command of an unsupported type: {:?}"
|
|
815
|
-
c
|
|
936
|
+
"A machine requested to create a new command of an unsupported type: {c:?}"
|
|
816
937
|
)))
|
|
817
938
|
}
|
|
818
939
|
},
|
|
@@ -849,7 +970,7 @@ impl WorkflowMachines {
|
|
|
849
970
|
Duration::from_secs(0),
|
|
850
971
|
removed_act.attempt,
|
|
851
972
|
None,
|
|
852
|
-
|
|
973
|
+
removed_act.original_schedule_time,
|
|
853
974
|
)?;
|
|
854
975
|
self.process_machine_responses(smk, more_responses)?;
|
|
855
976
|
} else {
|
|
@@ -916,7 +1037,11 @@ impl WorkflowMachines {
|
|
|
916
1037
|
}
|
|
917
1038
|
WFCommand::UpsertSearchAttributes(attrs) => {
|
|
918
1039
|
self.add_cmd_to_wf_task(
|
|
919
|
-
upsert_search_attrs(
|
|
1040
|
+
upsert_search_attrs(
|
|
1041
|
+
attrs,
|
|
1042
|
+
self.observed_internal_flags.clone(),
|
|
1043
|
+
self.replaying,
|
|
1044
|
+
),
|
|
920
1045
|
CommandIdKind::NeverResolves,
|
|
921
1046
|
);
|
|
922
1047
|
}
|
|
@@ -925,7 +1050,10 @@ impl WorkflowMachines {
|
|
|
925
1050
|
}
|
|
926
1051
|
WFCommand::AddActivity(attrs) => {
|
|
927
1052
|
let seq = attrs.seq;
|
|
928
|
-
self.add_cmd_to_wf_task(
|
|
1053
|
+
self.add_cmd_to_wf_task(
|
|
1054
|
+
ActivityMachine::new_scheduled(attrs, self.observed_internal_flags.clone()),
|
|
1055
|
+
CommandID::Activity(seq).into(),
|
|
1056
|
+
);
|
|
929
1057
|
}
|
|
930
1058
|
WFCommand::AddLocalActivity(attrs) => {
|
|
931
1059
|
let seq = attrs.seq;
|
|
@@ -937,8 +1065,7 @@ impl WorkflowMachines {
|
|
|
937
1065
|
)
|
|
938
1066
|
.map_err(|e| {
|
|
939
1067
|
WFMachinesError::Fatal(format!(
|
|
940
|
-
"Invalid schedule local activity request (seq {}): {}"
|
|
941
|
-
seq, e
|
|
1068
|
+
"Invalid schedule local activity request (seq {seq}): {e}"
|
|
942
1069
|
))
|
|
943
1070
|
})?;
|
|
944
1071
|
let (la, mach_resp) = new_local_activity(
|
|
@@ -946,6 +1073,7 @@ impl WorkflowMachines {
|
|
|
946
1073
|
self.replaying,
|
|
947
1074
|
self.local_activity_data.take_preresolution(seq),
|
|
948
1075
|
self.current_wf_time,
|
|
1076
|
+
self.observed_internal_flags.clone(),
|
|
949
1077
|
)?;
|
|
950
1078
|
let machkey = self.all_machines.insert(la.into());
|
|
951
1079
|
self.id_to_machine
|
|
@@ -978,13 +1106,21 @@ impl WorkflowMachines {
|
|
|
978
1106
|
WFCommand::SetPatchMarker(attrs) => {
|
|
979
1107
|
// Do not create commands for change IDs that we have already created commands
|
|
980
1108
|
// for.
|
|
981
|
-
|
|
1109
|
+
let encountered_entry = self.encountered_change_markers.get(&attrs.patch_id);
|
|
1110
|
+
if !matches!(encountered_entry,
|
|
982
1111
|
Some(ChangeInfo {created_command}) if *created_command)
|
|
983
1112
|
{
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1113
|
+
let (patch_machine, other_cmds) = has_change(
|
|
1114
|
+
attrs.patch_id.clone(),
|
|
1115
|
+
self.replaying,
|
|
1116
|
+
attrs.deprecated,
|
|
1117
|
+
encountered_entry.is_some(),
|
|
1118
|
+
self.encountered_change_markers.keys().map(|s| s.as_str()),
|
|
1119
|
+
self.observed_internal_flags.clone(),
|
|
1120
|
+
)?;
|
|
1121
|
+
let mkey =
|
|
1122
|
+
self.add_cmd_to_wf_task(patch_machine, CommandIdKind::NeverResolves);
|
|
1123
|
+
self.process_machine_responses(mkey, other_cmds)?;
|
|
988
1124
|
|
|
989
1125
|
if let Some(ci) = self.encountered_change_markers.get_mut(&attrs.patch_id) {
|
|
990
1126
|
ci.created_command = true;
|
|
@@ -1001,7 +1137,10 @@ impl WorkflowMachines {
|
|
|
1001
1137
|
WFCommand::AddChildWorkflow(attrs) => {
|
|
1002
1138
|
let seq = attrs.seq;
|
|
1003
1139
|
self.add_cmd_to_wf_task(
|
|
1004
|
-
|
|
1140
|
+
ChildWorkflowMachine::new_scheduled(
|
|
1141
|
+
attrs,
|
|
1142
|
+
self.observed_internal_flags.clone(),
|
|
1143
|
+
),
|
|
1005
1144
|
CommandID::ChildWorkflowStart(seq).into(),
|
|
1006
1145
|
);
|
|
1007
1146
|
}
|
|
@@ -1075,7 +1214,7 @@ impl WorkflowMachines {
|
|
|
1075
1214
|
|
|
1076
1215
|
fn get_machine_key(&self, id: CommandID) -> Result<MachineKey> {
|
|
1077
1216
|
Ok(*self.id_to_machine.get(&id).ok_or_else(|| {
|
|
1078
|
-
WFMachinesError::Fatal(format!("Missing associated machine for {:?}"
|
|
1217
|
+
WFMachinesError::Fatal(format!("Missing associated machine for {id:?}"))
|
|
1079
1218
|
})?)
|
|
1080
1219
|
}
|
|
1081
1220
|
|
|
@@ -1086,15 +1225,21 @@ impl WorkflowMachines {
|
|
|
1086
1225
|
}
|
|
1087
1226
|
|
|
1088
1227
|
/// Add a new command/machines for that command to the current workflow task
|
|
1089
|
-
fn add_cmd_to_wf_task(
|
|
1228
|
+
fn add_cmd_to_wf_task(
|
|
1229
|
+
&mut self,
|
|
1230
|
+
machine: NewMachineWithCommand,
|
|
1231
|
+
id: CommandIdKind,
|
|
1232
|
+
) -> MachineKey {
|
|
1090
1233
|
let mach = self.add_new_command_machine(machine);
|
|
1234
|
+
let key = mach.machine;
|
|
1091
1235
|
if let CommandIdKind::LangIssued(id) = id {
|
|
1092
|
-
self.id_to_machine.insert(id,
|
|
1236
|
+
self.id_to_machine.insert(id, key);
|
|
1093
1237
|
}
|
|
1094
1238
|
if matches!(id, CommandIdKind::CoreInternal) {
|
|
1095
|
-
self.machine_is_core_created.insert(
|
|
1239
|
+
self.machine_is_core_created.insert(key, ());
|
|
1096
1240
|
}
|
|
1097
1241
|
self.current_wf_task_commands.push_back(mach);
|
|
1242
|
+
key
|
|
1098
1243
|
}
|
|
1099
1244
|
|
|
1100
1245
|
fn add_new_command_machine(&mut self, machine: NewMachineWithCommand) -> CommandAndMachine {
|
|
@@ -1154,15 +1299,20 @@ fn str_to_randomness_seed(run_id: &str) -> u64 {
|
|
|
1154
1299
|
s.finish()
|
|
1155
1300
|
}
|
|
1156
1301
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1302
|
+
#[must_use]
|
|
1303
|
+
enum EventHandlingOutcome {
|
|
1304
|
+
SkipEvent { skip_next_event: bool },
|
|
1159
1305
|
SkipCommand,
|
|
1160
1306
|
Normal,
|
|
1161
1307
|
}
|
|
1162
1308
|
|
|
1163
1309
|
/// Special handling for patch markers, when handling command events as in
|
|
1164
1310
|
/// [WorkflowMachines::handle_command_event]
|
|
1165
|
-
fn change_marker_handling(
|
|
1311
|
+
fn change_marker_handling(
|
|
1312
|
+
event: &HistoryEvent,
|
|
1313
|
+
mach: &Machines,
|
|
1314
|
+
next_event: Option<&HistoryEvent>,
|
|
1315
|
+
) -> Result<EventHandlingOutcome> {
|
|
1166
1316
|
if !mach.matches_event(event) {
|
|
1167
1317
|
// Version markers can be skipped in the event they are deprecated
|
|
1168
1318
|
if let Some((patch_name, deprecated)) = event.get_patch_marker_details() {
|
|
@@ -1170,12 +1320,22 @@ fn change_marker_handling(event: &HistoryEvent, mach: &Machines) -> Result<Chang
|
|
|
1170
1320
|
// markers are allowed without matching changed calls.
|
|
1171
1321
|
if deprecated {
|
|
1172
1322
|
debug!("Deprecated patch marker tried against wrong machine, skipping.");
|
|
1173
|
-
|
|
1323
|
+
|
|
1324
|
+
// Also ignore the subsequent upsert event if present
|
|
1325
|
+
let mut skip_next_event = false;
|
|
1326
|
+
if let Some(Attributes::UpsertWorkflowSearchAttributesEventAttributes(atts)) =
|
|
1327
|
+
next_event.and_then(|ne| ne.attributes.as_ref())
|
|
1328
|
+
{
|
|
1329
|
+
if let Some(ref sa) = atts.search_attributes {
|
|
1330
|
+
skip_next_event = sa.indexed_fields.contains_key(VERSION_SEARCH_ATTR_KEY);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
return Ok(EventHandlingOutcome::SkipEvent { skip_next_event });
|
|
1174
1335
|
}
|
|
1175
1336
|
return Err(WFMachinesError::Nondeterminism(format!(
|
|
1176
|
-
"Non-deprecated patch marker encountered for change {}, \
|
|
1177
|
-
but there is no corresponding change command!"
|
|
1178
|
-
patch_name
|
|
1337
|
+
"Non-deprecated patch marker encountered for change {patch_name}, \
|
|
1338
|
+
but there is no corresponding change command!"
|
|
1179
1339
|
)));
|
|
1180
1340
|
}
|
|
1181
1341
|
// Patch machines themselves may also not *have* matching markers, where non-deprecated
|
|
@@ -1183,10 +1343,10 @@ fn change_marker_handling(event: &HistoryEvent, mach: &Machines) -> Result<Chang
|
|
|
1183
1343
|
// worker.
|
|
1184
1344
|
if matches!(mach, Machines::PatchMachine(_)) {
|
|
1185
1345
|
debug!("Skipping non-matching event against patch machine");
|
|
1186
|
-
return Ok(
|
|
1346
|
+
return Ok(EventHandlingOutcome::SkipCommand);
|
|
1187
1347
|
}
|
|
1188
1348
|
}
|
|
1189
|
-
Ok(
|
|
1349
|
+
Ok(EventHandlingOutcome::Normal)
|
|
1190
1350
|
}
|
|
1191
1351
|
|
|
1192
1352
|
#[derive(derive_more::From)]
|