@temporalio/core-bridge 1.8.5 → 1.9.0-rc.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 +189 -152
- package/Cargo.toml +1 -0
- package/lib/index.d.ts +17 -44
- package/lib/index.js.map +1 -1
- package/package.json +3 -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/.github/workflows/heavy.yml +4 -0
- package/sdk-core/.github/workflows/per-pr.yml +96 -0
- package/sdk-core/ARCHITECTURE.md +1 -1
- package/sdk-core/Cargo.toml +6 -0
- package/sdk-core/README.md +37 -21
- package/sdk-core/client/Cargo.toml +6 -3
- package/sdk-core/client/src/lib.rs +272 -138
- package/sdk-core/client/src/metrics.rs +68 -57
- package/sdk-core/client/src/raw.rs +191 -45
- package/sdk-core/client/src/retry.rs +20 -0
- package/sdk-core/client/src/worker_registry/mod.rs +264 -0
- package/sdk-core/client/src/workflow_handle/mod.rs +2 -1
- package/sdk-core/core/Cargo.toml +16 -18
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -7
- package/sdk-core/core/src/core_tests/mod.rs +1 -0
- package/sdk-core/core/src/core_tests/replay_flag.rs +29 -39
- package/sdk-core/core/src/core_tests/updates.rs +73 -0
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +52 -1
- package/sdk-core/core/src/ephemeral_server/mod.rs +34 -11
- package/sdk-core/core/src/internal_flags.rs +7 -1
- package/sdk-core/core/src/lib.rs +19 -36
- package/sdk-core/core/src/protosext/mod.rs +11 -3
- package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
- package/sdk-core/core/src/replay/mod.rs +100 -48
- package/sdk-core/core/src/telemetry/log_export.rs +161 -28
- package/sdk-core/core/src/telemetry/metrics.rs +869 -248
- package/sdk-core/core/src/telemetry/mod.rs +135 -239
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
- package/sdk-core/core/src/test_help/mod.rs +63 -4
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +12 -2
- package/sdk-core/core/src/worker/activities.rs +276 -10
- package/sdk-core/core/src/worker/client/mocks.rs +18 -0
- package/sdk-core/core/src/worker/client.rs +16 -3
- package/sdk-core/core/src/worker/mod.rs +50 -19
- package/sdk-core/core/src/worker/slot_provider.rs +175 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +27 -34
- package/sdk-core/core/src/worker/workflow/history_update.rs +4 -1
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +36 -94
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +34 -22
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +50 -34
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +106 -92
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +22 -21
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +386 -499
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -2
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +33 -26
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +198 -215
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +66 -62
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +88 -119
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +3 -1
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +411 -0
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +26 -25
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +302 -85
- package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
- package/sdk-core/core/src/worker/workflow/mod.rs +121 -46
- package/sdk-core/core/src/worker/workflow/run_cache.rs +8 -12
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +45 -38
- package/sdk-core/core-api/Cargo.toml +7 -6
- package/sdk-core/core-api/src/lib.rs +4 -12
- package/sdk-core/core-api/src/telemetry/metrics.rs +334 -0
- package/sdk-core/core-api/src/telemetry.rs +53 -42
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/{.buildkite/docker → docker}/docker-compose.yaml +1 -1
- package/sdk-core/etc/dynamic-config.yaml +11 -1
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +1 -3
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +2 -2
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +85 -7
- package/sdk-core/sdk/src/workflow_context/options.rs +4 -0
- package/sdk-core/sdk/src/workflow_context.rs +43 -15
- package/sdk-core/sdk/src/workflow_future.rs +334 -204
- package/sdk-core/sdk-core-protos/Cargo.toml +2 -2
- package/sdk-core/sdk-core-protos/build.rs +14 -14
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +99 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +56 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.gen.yaml +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +18 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/annotations.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/http.proto +379 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/any.proto +162 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/descriptor.proto +1212 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/duration.proto +115 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/empty.proto +51 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/timestamp.proto +144 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/wrappers.proto +123 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/batch/v1/message.proto +3 -5
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/command/v1/message.proto +11 -13
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/common/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/reset.proto +1 -1
- package/sdk-core/{protos/api_upstream/build/tools.go → sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto} +22 -6
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/filter/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/history/v1/message.proto +21 -23
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/namespace/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/replication/v1/message.proto +1 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/schedule/v1/message.proto +36 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +13 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/update/v1/message.proto +1 -1
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/version/v1/message.proto +2 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflow/v1/message.proto +18 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/request_response.proto +84 -32
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/service.proto +205 -47
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +57 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +27 -0
- package/sdk-core/sdk-core-protos/src/history_builder.rs +67 -2
- package/sdk-core/sdk-core-protos/src/lib.rs +75 -2
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +5 -1
- package/sdk-core/test-utils/src/canned_histories.rs +3 -57
- package/sdk-core/test-utils/src/interceptors.rs +46 -0
- package/sdk-core/test-utils/src/lib.rs +106 -38
- package/sdk-core/tests/integ_tests/metrics_tests.rs +110 -15
- package/sdk-core/tests/integ_tests/queries_tests.rs +174 -3
- package/sdk-core/tests/integ_tests/update_tests.rs +908 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +44 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +61 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +27 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
- package/sdk-core/tests/main.rs +2 -1
- package/sdk-core/tests/runner.rs +15 -2
- package/src/conversions.rs +75 -89
- package/src/helpers.rs +74 -0
- package/src/runtime.rs +17 -6
- package/src/worker.rs +14 -61
- package/ts/index.ts +21 -52
- package/sdk-core/.buildkite/docker/Dockerfile +0 -9
- package/sdk-core/.buildkite/docker/build.sh +0 -5
- package/sdk-core/.buildkite/docker/docker-compose-ci.yaml +0 -27
- package/sdk-core/.buildkite/pipeline.yml +0 -57
- package/sdk-core/.github/workflows/semgrep.yml +0 -25
- package/sdk-core/core/src/worker/workflow/bridge.rs +0 -35
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +0 -215
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/protos/api_upstream/Makefile +0 -80
- package/sdk-core/protos/api_upstream/api-linter.yaml +0 -40
- package/sdk-core/protos/api_upstream/buf.yaml +0 -9
- package/sdk-core/protos/api_upstream/build/go.mod +0 -7
- package/sdk-core/protos/api_upstream/build/go.sum +0 -5
- package/sdk-core/protos/api_upstream/go.mod +0 -6
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
- /package/sdk-core/{.buildkite/docker → docker}/docker-compose-telem.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/docker-compose.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/pipeline.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/CODEOWNERS +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/publish-docs.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/LICENSE +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/README.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/query.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/update.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/failure/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/query/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/google/rpc/status.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/grpc/health/v1/health.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/common/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/core_interface.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/external_data/external_data.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/Makefile +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/api-linter.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/buf.yaml +0 -0
- /package/sdk-core/{protos/api_upstream → sdk-core-protos/protos/testsrv_upstream}/dependencies/gogoproto/gogo.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
|
@@ -13,8 +13,12 @@ use super::{
|
|
|
13
13
|
TemporalStateMachine,
|
|
14
14
|
};
|
|
15
15
|
use crate::{
|
|
16
|
+
abstractions::dbg_panic,
|
|
16
17
|
internal_flags::InternalFlags,
|
|
17
|
-
protosext::{
|
|
18
|
+
protosext::{
|
|
19
|
+
protocol_messages::{IncomingProtocolMessage, IncomingProtocolMessageBody},
|
|
20
|
+
CompleteLocalActivityData, HistoryEventExt, ValidScheduleLA,
|
|
21
|
+
},
|
|
18
22
|
telemetry::{metrics::MetricsContext, VecDisplayer},
|
|
19
23
|
worker::{
|
|
20
24
|
workflow::{
|
|
@@ -23,13 +27,12 @@ use crate::{
|
|
|
23
27
|
activity_state_machine::ActivityMachine,
|
|
24
28
|
child_workflow_state_machine::ChildWorkflowMachine,
|
|
25
29
|
modify_workflow_properties_state_machine::modify_workflow_properties,
|
|
26
|
-
patch_state_machine::VERSION_SEARCH_ATTR_KEY,
|
|
30
|
+
patch_state_machine::VERSION_SEARCH_ATTR_KEY, update_state_machine::UpdateMachine,
|
|
27
31
|
upsert_search_attributes_state_machine::upsert_search_attrs_internal,
|
|
28
32
|
HistEventData,
|
|
29
33
|
},
|
|
30
34
|
CommandID, DrivenWorkflow, HistoryUpdate, InternalFlagsRef, LocalResolution,
|
|
31
|
-
OutgoingJob, RunBasics, WFCommand, WFMachinesError,
|
|
32
|
-
WorkflowStartedInfo,
|
|
35
|
+
OutgoingJob, RunBasics, WFCommand, WFMachinesError, WorkflowStartedInfo,
|
|
33
36
|
},
|
|
34
37
|
ExecutingLAId, LocalActRequest, LocalActivityExecutionResult, LocalActivityResolution,
|
|
35
38
|
},
|
|
@@ -37,11 +40,11 @@ use crate::{
|
|
|
37
40
|
use siphasher::sip::SipHasher13;
|
|
38
41
|
use slotmap::{SlotMap, SparseSecondaryMap};
|
|
39
42
|
use std::{
|
|
40
|
-
borrow::{Borrow, BorrowMut},
|
|
41
43
|
cell::RefCell,
|
|
42
44
|
collections::{HashMap, VecDeque},
|
|
43
45
|
convert::TryInto,
|
|
44
46
|
hash::{Hash, Hasher},
|
|
47
|
+
iter::Peekable,
|
|
45
48
|
rc::Rc,
|
|
46
49
|
time::{Duration, Instant, SystemTime},
|
|
47
50
|
};
|
|
@@ -59,7 +62,8 @@ use temporal_sdk_core_protos::{
|
|
|
59
62
|
temporal::api::{
|
|
60
63
|
command::v1::{command::Attributes as ProtoCmdAttrs, Command as ProtoCommand},
|
|
61
64
|
enums::v1::EventType,
|
|
62
|
-
history::v1::{history_event,
|
|
65
|
+
history::v1::{history_event, HistoryEvent},
|
|
66
|
+
protocol::v1::{message::SequencingId, Message as ProtocolMessage},
|
|
63
67
|
sdk::v1::WorkflowTaskCompletedMetadata,
|
|
64
68
|
},
|
|
65
69
|
};
|
|
@@ -75,6 +79,8 @@ pub(crate) struct WorkflowMachines {
|
|
|
75
79
|
/// kept because the lang side polls & completes for every workflow task, but we do not need
|
|
76
80
|
/// to poll the server that often during replay.
|
|
77
81
|
last_history_from_server: HistoryUpdate,
|
|
82
|
+
/// Protocol messages that have yet to be processed for the current WFT.
|
|
83
|
+
protocol_msgs: Vec<IncomingProtocolMessage>,
|
|
78
84
|
/// EventId of the last handled WorkflowTaskStarted event
|
|
79
85
|
current_started_event_id: i64,
|
|
80
86
|
/// The event id of the next workflow task started event that the machines need to process.
|
|
@@ -88,7 +94,7 @@ pub(crate) struct WorkflowMachines {
|
|
|
88
94
|
/// True if the workflow is replaying from history
|
|
89
95
|
pub replaying: bool,
|
|
90
96
|
/// Namespace this workflow exists in
|
|
91
|
-
|
|
97
|
+
namespace: String,
|
|
92
98
|
/// Workflow identifier
|
|
93
99
|
pub workflow_id: String,
|
|
94
100
|
/// Workflow type identifier. (Function name, class, etc)
|
|
@@ -96,7 +102,7 @@ pub(crate) struct WorkflowMachines {
|
|
|
96
102
|
/// Identifies the current run
|
|
97
103
|
pub run_id: String,
|
|
98
104
|
/// The task queue this workflow is operating within
|
|
99
|
-
|
|
105
|
+
task_queue: String,
|
|
100
106
|
/// Is set to true once we've seen the final event in workflow history, to avoid accidentally
|
|
101
107
|
/// re-applying the final workflow task.
|
|
102
108
|
pub have_seen_terminal_event: bool,
|
|
@@ -117,16 +123,19 @@ pub(crate) struct WorkflowMachines {
|
|
|
117
123
|
history_size_bytes: u64,
|
|
118
124
|
/// Set on each WFT started event
|
|
119
125
|
continue_as_new_suggested: bool,
|
|
126
|
+
/// Set if the current WFT is already complete and that completion event had a build id in it.
|
|
127
|
+
current_wft_build_id: Option<String>,
|
|
120
128
|
|
|
121
129
|
all_machines: SlotMap<MachineKey, Machines>,
|
|
122
130
|
/// If a machine key is in this map, that machine was created internally by core, not as a
|
|
123
131
|
/// command from lang.
|
|
124
132
|
machine_is_core_created: SparseSecondaryMap<MachineKey, ()>,
|
|
125
|
-
|
|
126
133
|
/// A mapping for accessing machines associated to a particular event, where the key is the id
|
|
127
134
|
/// of the initiating event for that machine.
|
|
128
135
|
machines_by_event_id: HashMap<i64, MachineKey>,
|
|
129
|
-
|
|
136
|
+
/// A mapping for accessing machines that were created as a result of protocol messages. The
|
|
137
|
+
/// key is the protocol's instance id.
|
|
138
|
+
machines_by_protocol_instance_id: HashMap<String, MachineKey>,
|
|
130
139
|
/// Maps command ids as created by workflow authors to their associated machines.
|
|
131
140
|
id_to_machine: HashMap<CommandID, MachineKey>,
|
|
132
141
|
|
|
@@ -136,6 +145,9 @@ pub(crate) struct WorkflowMachines {
|
|
|
136
145
|
/// Commands generated by the currently processing workflow task, which will eventually be
|
|
137
146
|
/// transferred to `commands` (and hence eventually sent to the server)
|
|
138
147
|
current_wf_task_commands: VecDeque<CommandAndMachine>,
|
|
148
|
+
/// Messages generated while processing the current workflow task, which will be sent in the
|
|
149
|
+
/// next WFT response. Keyed by message id.
|
|
150
|
+
message_outbox: VecDeque<ProtocolMessage>,
|
|
139
151
|
|
|
140
152
|
/// Information about patch markers we have already seen while replaying history
|
|
141
153
|
encountered_patch_markers: HashMap<String, ChangeInfo>,
|
|
@@ -180,6 +192,9 @@ pub(super) enum MachineResponse {
|
|
|
180
192
|
/// Pushes a new command into the list that will be sent to server once we respond with the
|
|
181
193
|
/// workflow task completion
|
|
182
194
|
IssueNewCommand(ProtoCommand),
|
|
195
|
+
/// Pushes a new protocol message into the list that will be sent to server once we respond with
|
|
196
|
+
/// the workflow task completion
|
|
197
|
+
IssueNewMessage(ProtocolMessage),
|
|
183
198
|
/// The machine requests the creation of another *different* machine. This acts as if lang
|
|
184
199
|
/// had replied to the activation with a command, but we use a special set of IDs to avoid
|
|
185
200
|
/// collisions.
|
|
@@ -230,6 +245,7 @@ impl WorkflowMachines {
|
|
|
230
245
|
};
|
|
231
246
|
Self {
|
|
232
247
|
last_history_from_server: basics.history,
|
|
248
|
+
protocol_msgs: vec![],
|
|
233
249
|
namespace: basics.namespace,
|
|
234
250
|
workflow_id: basics.workflow_id,
|
|
235
251
|
workflow_type: basics.workflow_type,
|
|
@@ -249,12 +265,15 @@ impl WorkflowMachines {
|
|
|
249
265
|
observed_internal_flags: Rc::new(RefCell::new(observed_internal_flags)),
|
|
250
266
|
history_size_bytes: 0,
|
|
251
267
|
continue_as_new_suggested: false,
|
|
268
|
+
current_wft_build_id: None,
|
|
252
269
|
all_machines: Default::default(),
|
|
253
270
|
machine_is_core_created: Default::default(),
|
|
254
271
|
machines_by_event_id: Default::default(),
|
|
272
|
+
machines_by_protocol_instance_id: Default::default(),
|
|
255
273
|
id_to_machine: Default::default(),
|
|
256
274
|
commands: Default::default(),
|
|
257
275
|
current_wf_task_commands: Default::default(),
|
|
276
|
+
message_outbox: Default::default(),
|
|
258
277
|
encountered_patch_markers: Default::default(),
|
|
259
278
|
local_activity_data: LocalActivityData::default(),
|
|
260
279
|
have_seen_terminal_event: false,
|
|
@@ -274,6 +293,20 @@ impl WorkflowMachines {
|
|
|
274
293
|
.and_then(|(st, et)| et.duration_since(st).ok())
|
|
275
294
|
}
|
|
276
295
|
|
|
296
|
+
/// Must be called every time a new WFT is received
|
|
297
|
+
pub(crate) fn new_work_from_server(
|
|
298
|
+
&mut self,
|
|
299
|
+
update: HistoryUpdate,
|
|
300
|
+
protocol_messages: Vec<IncomingProtocolMessage>,
|
|
301
|
+
) -> Result<()> {
|
|
302
|
+
if !self.protocol_msgs.is_empty() {
|
|
303
|
+
dbg_panic!("There are unprocessed protocol messages while receiving new work");
|
|
304
|
+
}
|
|
305
|
+
self.protocol_msgs = protocol_messages;
|
|
306
|
+
self.new_history_from_server(update)?;
|
|
307
|
+
Ok(())
|
|
308
|
+
}
|
|
309
|
+
|
|
277
310
|
pub(crate) fn new_history_from_server(&mut self, update: HistoryUpdate) -> Result<()> {
|
|
278
311
|
self.last_history_from_server = update;
|
|
279
312
|
self.replaying = self.last_history_from_server.previous_wft_started_id > 0;
|
|
@@ -335,28 +368,40 @@ impl WorkflowMachines {
|
|
|
335
368
|
self.drive_me.get_started_info()
|
|
336
369
|
}
|
|
337
370
|
|
|
371
|
+
pub(crate) fn get_last_wft_started_id(&self) -> i64 {
|
|
372
|
+
self.current_started_event_id
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
pub(crate) fn prepare_for_wft_response(&mut self) -> MachinesWFTResponseContent {
|
|
376
|
+
MachinesWFTResponseContent {
|
|
377
|
+
replaying: self.replaying,
|
|
378
|
+
has_pending_jobs: self.has_pending_jobs(),
|
|
379
|
+
have_seen_terminal_event: self.have_seen_terminal_event,
|
|
380
|
+
have_pending_la_resolutions: self.has_pending_la_resolutions(),
|
|
381
|
+
last_processed_event: self.last_processed_event,
|
|
382
|
+
me: self,
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
338
386
|
/// Fetches commands which are ready for processing from the state machines, generally to be
|
|
339
387
|
/// sent off to the server. They are not removed from the internal queue, that happens when
|
|
340
388
|
/// corresponding history events from the server are being handled.
|
|
341
|
-
pub(crate) fn get_commands(&self) ->
|
|
389
|
+
pub(crate) fn get_commands(&self) -> impl Iterator<Item = ProtoCommand> + '_ {
|
|
342
390
|
// Since we're about to write a WFT, record any internal flags we know about which aren't
|
|
343
391
|
// already recorded.
|
|
344
392
|
(*self.observed_internal_flags)
|
|
345
393
|
.borrow_mut()
|
|
346
394
|
.write_all_known();
|
|
347
|
-
self.commands
|
|
348
|
-
.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
MachineAssociatedCommand::Real(cmd) => Some((**cmd).clone()),
|
|
353
|
-
MachineAssociatedCommand::FakeLocalActivityMarker(_) => None,
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
None
|
|
395
|
+
self.commands.iter().filter_map(|c| {
|
|
396
|
+
if !self.machine(c.machine).is_final_state() {
|
|
397
|
+
match &c.command {
|
|
398
|
+
MachineAssociatedCommand::Real(cmd) => Some((**cmd).clone()),
|
|
399
|
+
MachineAssociatedCommand::FakeLocalActivityMarker(_) => None,
|
|
357
400
|
}
|
|
358
|
-
}
|
|
359
|
-
|
|
401
|
+
} else {
|
|
402
|
+
None
|
|
403
|
+
}
|
|
404
|
+
})
|
|
360
405
|
}
|
|
361
406
|
|
|
362
407
|
/// Returns the next activation that needs to be performed by the lang sdk. Things like unblock
|
|
@@ -387,6 +432,7 @@ impl WorkflowMachines {
|
|
|
387
432
|
.collect(),
|
|
388
433
|
history_size_bytes: self.history_size_bytes,
|
|
389
434
|
continue_as_new_suggested: self.continue_as_new_suggested,
|
|
435
|
+
build_id_for_current_task: self.current_wft_build_id.clone().unwrap_or_default(),
|
|
390
436
|
}
|
|
391
437
|
}
|
|
392
438
|
|
|
@@ -413,6 +459,30 @@ impl WorkflowMachines {
|
|
|
413
459
|
.add_lang_used(flags);
|
|
414
460
|
}
|
|
415
461
|
|
|
462
|
+
/// Undo a speculative workflow task by resetting to a certain WFT Started ID. This can happen
|
|
463
|
+
/// when an update request is rejected.
|
|
464
|
+
pub(crate) fn reset_last_started_id(&mut self, id: i64) {
|
|
465
|
+
debug!("Resetting back to event id {} due to speculative WFT", id);
|
|
466
|
+
self.current_started_event_id = id;
|
|
467
|
+
// This is pretty nasty to just + 1 like this, but, we know WFT complete always follows
|
|
468
|
+
// WFT started, which the id given to us to reset to must be, and we need to avoid
|
|
469
|
+
// re-applying the WFT Completed event, so we make sure to consider that processed
|
|
470
|
+
self.last_processed_event = id + 1;
|
|
471
|
+
// Then, we have to drop any state machines (which should only be one workflow task machine)
|
|
472
|
+
// we may have created when servicing the speculative task.
|
|
473
|
+
// Remove when https://github.com/rust-lang/rust/issues/59618 is stable
|
|
474
|
+
let remove_these: Vec<_> = self
|
|
475
|
+
.machines_by_event_id
|
|
476
|
+
.iter()
|
|
477
|
+
.filter(|(mid, _)| **mid > id)
|
|
478
|
+
.map(|(mid, mkey)| (*mid, *mkey))
|
|
479
|
+
.collect();
|
|
480
|
+
for (mid, mkey) in remove_these {
|
|
481
|
+
self.machines_by_event_id.remove(&mid);
|
|
482
|
+
self.all_machines.remove(mkey);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
416
486
|
/// Iterate the state machines, which consists of grabbing any pending outgoing commands from
|
|
417
487
|
/// the workflow code, handling them, and preparing them to be sent off to the server.
|
|
418
488
|
pub(crate) fn iterate_machines(&mut self) -> Result<()> {
|
|
@@ -446,22 +516,45 @@ impl WorkflowMachines {
|
|
|
446
516
|
return Ok(0);
|
|
447
517
|
}
|
|
448
518
|
|
|
449
|
-
fn
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
519
|
+
fn get_processable_messages(
|
|
520
|
+
me: &mut WorkflowMachines,
|
|
521
|
+
for_event_id: i64,
|
|
522
|
+
) -> Vec<IncomingProtocolMessage> {
|
|
523
|
+
// Another thing to replace when `drain_filter` exists
|
|
524
|
+
let mut ret = vec![];
|
|
525
|
+
me.protocol_msgs = std::mem::take(&mut me.protocol_msgs)
|
|
526
|
+
.into_iter()
|
|
527
|
+
.filter_map(|x| {
|
|
528
|
+
if x.processable_after_event_id()
|
|
529
|
+
.is_some_and(|eid| eid <= for_event_id)
|
|
530
|
+
{
|
|
531
|
+
ret.push(x);
|
|
532
|
+
None
|
|
533
|
+
} else {
|
|
534
|
+
Some(x)
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
.collect();
|
|
538
|
+
ret
|
|
459
539
|
}
|
|
460
540
|
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
541
|
+
// Peek to the next WFT complete and update ourselves with data we might need in it.
|
|
542
|
+
if let Some(next_complete) = self
|
|
543
|
+
.last_history_from_server
|
|
544
|
+
.peek_next_wft_completed(self.last_processed_event)
|
|
545
|
+
{
|
|
546
|
+
// We update the internal flags before applying the current task
|
|
547
|
+
(*self.observed_internal_flags)
|
|
548
|
+
.borrow_mut()
|
|
549
|
+
.add_from_complete(next_complete);
|
|
550
|
+
// Save this tasks' Build ID if it had one
|
|
551
|
+
if let Some(bid) = next_complete.worker_version.as_ref().map(|wv| &wv.build_id) {
|
|
552
|
+
self.current_wft_build_id = Some(bid.to_string());
|
|
553
|
+
} else {
|
|
554
|
+
// Otherwise we do not want to keep anything previously stored
|
|
555
|
+
self.current_wft_build_id = None;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
465
558
|
|
|
466
559
|
let last_handled_wft_started_id = self.current_started_event_id;
|
|
467
560
|
let (events, has_final_event) = match self
|
|
@@ -499,14 +592,14 @@ impl WorkflowMachines {
|
|
|
499
592
|
let mut do_handle_event = true;
|
|
500
593
|
let mut history = events.into_iter().peekable();
|
|
501
594
|
while let Some(event) = history.next() {
|
|
502
|
-
|
|
595
|
+
let eid = event.event_id;
|
|
596
|
+
if eid != self.last_processed_event + 1 {
|
|
503
597
|
return Err(WFMachinesError::Fatal(format!(
|
|
504
598
|
"History is out of order. Last processed event: {}, event id: {}",
|
|
505
|
-
self.last_processed_event,
|
|
599
|
+
self.last_processed_event, eid
|
|
506
600
|
)));
|
|
507
601
|
}
|
|
508
602
|
let next_event = history.peek();
|
|
509
|
-
let eid = event.event_id;
|
|
510
603
|
|
|
511
604
|
// This definition of replaying here is that we are no longer replaying as soon as we
|
|
512
605
|
// see new events that have never been seen or produced by the SDK.
|
|
@@ -520,7 +613,7 @@ impl WorkflowMachines {
|
|
|
520
613
|
// them.
|
|
521
614
|
if self.replaying
|
|
522
615
|
&& has_final_event
|
|
523
|
-
&&
|
|
616
|
+
&& eid > self.last_history_from_server.previous_wft_started_id
|
|
524
617
|
&& event.event_type() != EventType::WorkflowTaskCompleted
|
|
525
618
|
&& !event.is_command_event()
|
|
526
619
|
{
|
|
@@ -528,6 +621,12 @@ impl WorkflowMachines {
|
|
|
528
621
|
self.replaying = false;
|
|
529
622
|
}
|
|
530
623
|
|
|
624
|
+
// Process any messages that should be processed before the event we're about to handle
|
|
625
|
+
let processable_msgs = get_processable_messages(self, eid - 1);
|
|
626
|
+
for msg in processable_msgs {
|
|
627
|
+
self.handle_protocol_message(msg)?;
|
|
628
|
+
}
|
|
629
|
+
|
|
531
630
|
if do_handle_event {
|
|
532
631
|
let eho = self.handle_event(
|
|
533
632
|
HistEventData {
|
|
@@ -551,9 +650,14 @@ impl WorkflowMachines {
|
|
|
551
650
|
self.last_processed_event = eid;
|
|
552
651
|
}
|
|
553
652
|
|
|
653
|
+
// Needed to delay mutation of self until after we've iterated over peeked events.
|
|
654
|
+
enum DelayedAction {
|
|
655
|
+
WakeLa(MachineKey, CompleteLocalActivityData),
|
|
656
|
+
ProtocolMessage(IncomingProtocolMessage),
|
|
657
|
+
}
|
|
658
|
+
let mut delayed_actions = vec![];
|
|
554
659
|
// Scan through to the next WFT, searching for any patch / la markers, so that we can
|
|
555
660
|
// pre-resolve them.
|
|
556
|
-
let mut wake_las = vec![];
|
|
557
661
|
for e in self
|
|
558
662
|
.last_history_from_server
|
|
559
663
|
.peek_next_wft_sequence(last_handled_wft_started_id)
|
|
@@ -575,7 +679,7 @@ impl WorkflowMachines {
|
|
|
575
679
|
if let Ok(mk) =
|
|
576
680
|
self.get_machine_key(CommandID::LocalActivity(la_dat.marker_dat.seq))
|
|
577
681
|
{
|
|
578
|
-
|
|
682
|
+
delayed_actions.push(DelayedAction::WakeLa(mk, la_dat));
|
|
579
683
|
} else {
|
|
580
684
|
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
581
685
|
}
|
|
@@ -584,22 +688,51 @@ impl WorkflowMachines {
|
|
|
584
688
|
"Local activity marker was unparsable: {e:?}"
|
|
585
689
|
)));
|
|
586
690
|
}
|
|
691
|
+
} else if let Some(
|
|
692
|
+
history_event::Attributes::WorkflowExecutionUpdateAcceptedEventAttributes(ref atts),
|
|
693
|
+
) = e.attributes
|
|
694
|
+
{
|
|
695
|
+
// If we see a workflow update accepted event, initialize the machine for it by
|
|
696
|
+
// pretending we received the message we would've under not-replay.
|
|
697
|
+
delayed_actions.push(DelayedAction::ProtocolMessage(IncomingProtocolMessage {
|
|
698
|
+
id: atts.accepted_request_message_id.clone(),
|
|
699
|
+
protocol_instance_id: atts.protocol_instance_id.clone(),
|
|
700
|
+
sequencing_id: Some(SequencingId::EventId(
|
|
701
|
+
atts.accepted_request_sequencing_event_id,
|
|
702
|
+
)),
|
|
703
|
+
body: IncomingProtocolMessageBody::UpdateRequest(
|
|
704
|
+
atts.accepted_request
|
|
705
|
+
.clone()
|
|
706
|
+
.ok_or_else(|| {
|
|
707
|
+
WFMachinesError::Fatal(
|
|
708
|
+
"Update accepted event must contain accepted request"
|
|
709
|
+
.to_string(),
|
|
710
|
+
)
|
|
711
|
+
})?
|
|
712
|
+
.try_into()?,
|
|
713
|
+
),
|
|
714
|
+
}));
|
|
587
715
|
}
|
|
588
716
|
}
|
|
589
|
-
for
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
let
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
717
|
+
for action in delayed_actions {
|
|
718
|
+
match action {
|
|
719
|
+
DelayedAction::WakeLa(mk, la_dat) => {
|
|
720
|
+
let mach = self.machine_mut(mk);
|
|
721
|
+
if let Machines::LocalActivityMachine(ref mut lam) = *mach {
|
|
722
|
+
if lam.will_accept_resolve_marker() {
|
|
723
|
+
let resps = lam.try_resolve_with_dat(la_dat.into())?;
|
|
724
|
+
self.process_machine_responses(mk, resps)?;
|
|
725
|
+
} else {
|
|
726
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
DelayedAction::ProtocolMessage(pm) => {
|
|
731
|
+
self.handle_protocol_message(pm)?;
|
|
597
732
|
}
|
|
598
733
|
}
|
|
599
734
|
}
|
|
600
735
|
|
|
601
|
-
update_internal_flags(self);
|
|
602
|
-
|
|
603
736
|
if !self.replaying {
|
|
604
737
|
self.metrics.wf_task_replay_latency(replay_start.elapsed());
|
|
605
738
|
}
|
|
@@ -665,27 +798,19 @@ impl WorkflowMachines {
|
|
|
665
798
|
}
|
|
666
799
|
|
|
667
800
|
if let Some(initial_cmd_id) = event.get_initial_command_event_id() {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
self.submachine_handle_event(sm, event_dat)?;
|
|
674
|
-
// Restore machine if not in it's final state
|
|
675
|
-
if !self.machine(sm).is_final_state() {
|
|
676
|
-
self.machines_by_event_id.insert(initial_cmd_id, sm);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
None => {
|
|
680
|
-
return Err(WFMachinesError::Nondeterminism(format!(
|
|
801
|
+
let mkey = self
|
|
802
|
+
.machines_by_event_id
|
|
803
|
+
.get(&initial_cmd_id)
|
|
804
|
+
.ok_or_else(|| {
|
|
805
|
+
WFMachinesError::Nondeterminism(format!(
|
|
681
806
|
"During event handling, this event had an initial command ID but we \
|
|
682
|
-
|
|
683
|
-
))
|
|
684
|
-
}
|
|
685
|
-
|
|
807
|
+
could not find a matching command for it: {event:?}"
|
|
808
|
+
))
|
|
809
|
+
})?;
|
|
810
|
+
self.submachine_handle_event(*mkey, event_dat)?;
|
|
686
811
|
} else {
|
|
687
812
|
self.handle_non_stateful_event(event_dat)?;
|
|
688
|
-
}
|
|
813
|
+
};
|
|
689
814
|
|
|
690
815
|
Ok(EventHandlingOutcome::Normal)
|
|
691
816
|
}
|
|
@@ -769,10 +894,7 @@ impl WorkflowMachines {
|
|
|
769
894
|
}
|
|
770
895
|
|
|
771
896
|
fn handle_non_stateful_event(&mut self, event_dat: HistEventData) -> Result<()> {
|
|
772
|
-
trace!(
|
|
773
|
-
event = %event_dat.event,
|
|
774
|
-
"handling non-stateful event"
|
|
775
|
-
);
|
|
897
|
+
trace!(event = %event_dat.event, "handling non-stateful event");
|
|
776
898
|
let event_id = event_dat.event.event_id;
|
|
777
899
|
match EventType::from_i32(event_dat.event.event_type) {
|
|
778
900
|
Some(EventType::WorkflowExecutionStarted) => {
|
|
@@ -855,6 +977,42 @@ impl WorkflowMachines {
|
|
|
855
977
|
self.process_machine_responses(sm, machine_responses)?;
|
|
856
978
|
Ok(())
|
|
857
979
|
}
|
|
980
|
+
/// Handle a single protocol message delivered in a workflow task.
|
|
981
|
+
///
|
|
982
|
+
/// This function will attempt to apply the message to a corresponding state machine for the
|
|
983
|
+
/// appropriate protocol type, creating it if it does not exist.
|
|
984
|
+
///
|
|
985
|
+
/// On replay, protocol messages may be made up by looking ahead in history to see if there is
|
|
986
|
+
/// already an event corresponding to the result of some protocol message which would have
|
|
987
|
+
/// existed to create that result.
|
|
988
|
+
#[instrument(skip(self))]
|
|
989
|
+
fn handle_protocol_message(&mut self, message: IncomingProtocolMessage) -> Result<()> {
|
|
990
|
+
static SEQIDERR: &str = "Update request messages must contain an event sequencing id! \
|
|
991
|
+
This is a server bug.";
|
|
992
|
+
|
|
993
|
+
match message.body {
|
|
994
|
+
IncomingProtocolMessageBody::UpdateRequest(ur) => {
|
|
995
|
+
let seq_id = if let SequencingId::EventId(eid) = message
|
|
996
|
+
.sequencing_id
|
|
997
|
+
.ok_or_else(|| WFMachinesError::Fatal(SEQIDERR.to_string()))?
|
|
998
|
+
{
|
|
999
|
+
eid
|
|
1000
|
+
} else {
|
|
1001
|
+
return Err(WFMachinesError::Fatal(SEQIDERR.to_string()));
|
|
1002
|
+
};
|
|
1003
|
+
let um = UpdateMachine::init(
|
|
1004
|
+
message.id,
|
|
1005
|
+
message.protocol_instance_id.clone(),
|
|
1006
|
+
seq_id,
|
|
1007
|
+
ur,
|
|
1008
|
+
self.replaying,
|
|
1009
|
+
);
|
|
1010
|
+
let mk = self.add_new_protocol_machine(um.machine, message.protocol_instance_id);
|
|
1011
|
+
self.process_machine_responses(mk, vec![um.response])?;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
Ok(())
|
|
1015
|
+
}
|
|
858
1016
|
|
|
859
1017
|
/// Transfer commands from `current_wf_task_commands` to `commands`, so they may be sent off
|
|
860
1018
|
/// to the server. While doing so, [TemporalStateMachine::handle_command] is called on the
|
|
@@ -940,6 +1098,13 @@ impl WorkflowMachines {
|
|
|
940
1098
|
machine: smk,
|
|
941
1099
|
})
|
|
942
1100
|
}
|
|
1101
|
+
MachineResponse::IssueNewMessage(pm) => {
|
|
1102
|
+
// Messages shouldn't be sent back when replaying. This is true for update,
|
|
1103
|
+
// currently the only user of protocol messages. May eventually change.
|
|
1104
|
+
if !self.replaying {
|
|
1105
|
+
self.message_outbox.push_back(pm);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
943
1108
|
MachineResponse::NewCoreOriginatedCommand(attrs) => match attrs {
|
|
944
1109
|
ProtoCmdAttrs::RequestCancelExternalWorkflowExecutionCommandAttributes(
|
|
945
1110
|
attrs,
|
|
@@ -1244,6 +1409,20 @@ impl WorkflowMachines {
|
|
|
1244
1409
|
CommandIdKind::NeverResolves,
|
|
1245
1410
|
);
|
|
1246
1411
|
}
|
|
1412
|
+
WFCommand::UpdateResponse(ur) => {
|
|
1413
|
+
let m_key = self.get_machine_by_msg(&ur.protocol_instance_id)?;
|
|
1414
|
+
let mach = self.machine_mut(m_key);
|
|
1415
|
+
if let Machines::UpdateMachine(m) = mach {
|
|
1416
|
+
let resps = m.handle_response(ur)?;
|
|
1417
|
+
self.process_machine_responses(m_key, resps)?;
|
|
1418
|
+
} else {
|
|
1419
|
+
return Err(WFMachinesError::Nondeterminism(format!(
|
|
1420
|
+
"Tried to handle an update response for \
|
|
1421
|
+
update with instance id {} but it was not found!",
|
|
1422
|
+
&ur.protocol_instance_id
|
|
1423
|
+
)));
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1247
1426
|
WFCommand::NoCommandsFromLang => (),
|
|
1248
1427
|
}
|
|
1249
1428
|
}
|
|
@@ -1267,6 +1446,17 @@ impl WorkflowMachines {
|
|
|
1267
1446
|
})?)
|
|
1268
1447
|
}
|
|
1269
1448
|
|
|
1449
|
+
fn get_machine_by_msg(&self, protocol_instance_id: &str) -> Result<MachineKey> {
|
|
1450
|
+
Ok(*self
|
|
1451
|
+
.machines_by_protocol_instance_id
|
|
1452
|
+
.get(protocol_instance_id)
|
|
1453
|
+
.ok_or_else(|| {
|
|
1454
|
+
WFMachinesError::Fatal(format!(
|
|
1455
|
+
"Missing associated machine for protocol message {protocol_instance_id}"
|
|
1456
|
+
))
|
|
1457
|
+
})?)
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1270
1460
|
fn add_terminal_command(&mut self, machine: NewMachineWithCommand) {
|
|
1271
1461
|
let cwfm = self.add_new_command_machine(machine);
|
|
1272
1462
|
self.workflow_end_time = Some(SystemTime::now());
|
|
@@ -1299,18 +1489,18 @@ impl WorkflowMachines {
|
|
|
1299
1489
|
}
|
|
1300
1490
|
}
|
|
1301
1491
|
|
|
1492
|
+
fn add_new_protocol_machine(&mut self, machine: Machines, instance_id: String) -> MachineKey {
|
|
1493
|
+
let k = self.all_machines.insert(machine);
|
|
1494
|
+
self.machines_by_protocol_instance_id.insert(instance_id, k);
|
|
1495
|
+
k
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1302
1498
|
fn machine(&self, m: MachineKey) -> &Machines {
|
|
1303
|
-
self.all_machines
|
|
1304
|
-
.get(m)
|
|
1305
|
-
.expect("Machine must exist")
|
|
1306
|
-
.borrow()
|
|
1499
|
+
self.all_machines.get(m).expect("Machine must exist")
|
|
1307
1500
|
}
|
|
1308
1501
|
|
|
1309
1502
|
fn machine_mut(&mut self, m: MachineKey) -> &mut Machines {
|
|
1310
|
-
self.all_machines
|
|
1311
|
-
.get_mut(m)
|
|
1312
|
-
.expect("Machine must exist")
|
|
1313
|
-
.borrow_mut()
|
|
1503
|
+
self.all_machines.get_mut(m).expect("Machine must exist")
|
|
1314
1504
|
}
|
|
1315
1505
|
|
|
1316
1506
|
fn augment_continue_as_new_with_current_values(
|
|
@@ -1355,6 +1545,32 @@ impl WorkflowMachines {
|
|
|
1355
1545
|
}
|
|
1356
1546
|
}
|
|
1357
1547
|
|
|
1548
|
+
/// Contains everything workflow machine internals need to bubble up when we're getting ready to
|
|
1549
|
+
/// respond with a WFT completion. Allows for lazy mutation of the machine, since mutation is not
|
|
1550
|
+
/// desired unless we are actually going to respond to the WFT, which may not always happen.
|
|
1551
|
+
pub struct MachinesWFTResponseContent<'a> {
|
|
1552
|
+
me: &'a mut WorkflowMachines,
|
|
1553
|
+
pub replaying: bool,
|
|
1554
|
+
pub has_pending_jobs: bool,
|
|
1555
|
+
pub have_seen_terminal_event: bool,
|
|
1556
|
+
pub have_pending_la_resolutions: bool,
|
|
1557
|
+
pub last_processed_event: i64,
|
|
1558
|
+
}
|
|
1559
|
+
impl<'a> MachinesWFTResponseContent<'a> {
|
|
1560
|
+
pub fn commands(&self) -> Peekable<impl Iterator<Item = ProtoCommand> + '_> {
|
|
1561
|
+
self.me.get_commands().peekable()
|
|
1562
|
+
}
|
|
1563
|
+
pub fn has_messages(&self) -> bool {
|
|
1564
|
+
!self.me.message_outbox.is_empty()
|
|
1565
|
+
}
|
|
1566
|
+
pub fn messages(&mut self) -> Vec<ProtocolMessage> {
|
|
1567
|
+
self.me.message_outbox.drain(..).collect()
|
|
1568
|
+
}
|
|
1569
|
+
pub fn metadata_for_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
1570
|
+
self.me.get_metadata_for_wft_complete()
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1358
1574
|
fn str_to_randomness_seed(run_id: &str) -> u64 {
|
|
1359
1575
|
// This was originally `DefaultHasher` but that is potentially unstable across Rust releases.
|
|
1360
1576
|
// This must forever be `SipHasher13` now or we risk breaking history compat.
|
|
@@ -1385,8 +1601,9 @@ fn patch_marker_handling(
|
|
|
1385
1601
|
fn skip_one_or_two_events(next_event: Option<&HistoryEvent>) -> Result<EventHandlingOutcome> {
|
|
1386
1602
|
// Also ignore the subsequent upsert event if present
|
|
1387
1603
|
let mut skip_next_event = false;
|
|
1388
|
-
if let Some(Attributes::UpsertWorkflowSearchAttributesEventAttributes(
|
|
1389
|
-
|
|
1604
|
+
if let Some(history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(
|
|
1605
|
+
atts,
|
|
1606
|
+
)) = next_event.and_then(|ne| ne.attributes.as_ref())
|
|
1390
1607
|
{
|
|
1391
1608
|
if let Some(ref sa) = atts.search_attributes {
|
|
1392
1609
|
skip_next_event = sa.indexed_fields.contains_key(VERSION_SEARCH_ATTR_KEY);
|