@temporalio/core-bridge 1.8.6 → 1.9.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 +670 -594
- package/Cargo.toml +2 -1
- package/lib/errors.js +6 -6
- package/lib/errors.js.map +1 -1
- package/lib/index.d.ts +17 -44
- package/lib/index.js.map +1 -1
- package/package.json +5 -6
- 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 +10 -0
- package/sdk-core/LICENSE.txt +0 -2
- package/sdk-core/README.md +37 -21
- package/sdk-core/client/Cargo.toml +7 -4
- package/sdk-core/client/src/lib.rs +274 -142
- 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 +17 -19
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -2
- 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/queries.rs +42 -1
- 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 +12 -4
- package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
- package/sdk-core/core/src/replay/mod.rs +99 -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 +153 -257
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
- package/sdk-core/core/src/test_help/mod.rs +64 -5
- 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 +45 -28
- 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 +5 -2
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +71 -95
- 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 +67 -63
- 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 +27 -26
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +319 -94
- package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
- package/sdk-core/core/src/worker/workflow/mod.rs +129 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +16 -26
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +48 -43
- package/sdk-core/core-api/Cargo.toml +8 -7
- 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/LICENSE.txt +0 -2
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +0 -2
- 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/fsm/rustfsm_trait/LICENSE.txt +0 -2
- package/sdk-core/sdk/Cargo.toml +2 -2
- 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 +3 -3
- 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 +12 -9
- 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 +33 -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 +4 -4
- 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/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +66 -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 +24 -22
- 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/history_info.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +76 -3
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +6 -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/visibility_tests.rs +4 -4
- 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 +142 -3
- package/sdk-core/tests/main.rs +2 -1
- package/sdk-core/tests/runner.rs +15 -2
- package/src/conversions.rs +107 -96
- package/src/helpers.rs +74 -0
- package/src/runtime.rs +29 -15
- package/src/worker.rs +14 -61
- package/ts/index.ts +23 -54
- 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/client/LICENSE.txt +0 -23
- package/sdk-core/core/LICENSE.txt +0 -23
- 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/core-api/LICENSE.txt +0 -23
- 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/sdk/LICENSE.txt +0 -23
- package/sdk-core/sdk-core-protos/LICENSE.txt +0 -23
- /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,14 +40,16 @@ 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,
|
|
49
|
+
sync::Arc,
|
|
46
50
|
time::{Duration, Instant, SystemTime},
|
|
47
51
|
};
|
|
52
|
+
use temporal_sdk_core_api::worker::WorkerConfig;
|
|
48
53
|
use temporal_sdk_core_protos::{
|
|
49
54
|
coresdk::{
|
|
50
55
|
common::{NamespacedWorkflowExecution, VersioningIntent},
|
|
@@ -59,7 +64,8 @@ use temporal_sdk_core_protos::{
|
|
|
59
64
|
temporal::api::{
|
|
60
65
|
command::v1::{command::Attributes as ProtoCmdAttrs, Command as ProtoCommand},
|
|
61
66
|
enums::v1::EventType,
|
|
62
|
-
history::v1::{history_event,
|
|
67
|
+
history::v1::{history_event, HistoryEvent},
|
|
68
|
+
protocol::v1::{message::SequencingId, Message as ProtocolMessage},
|
|
63
69
|
sdk::v1::WorkflowTaskCompletedMetadata,
|
|
64
70
|
},
|
|
65
71
|
};
|
|
@@ -75,6 +81,8 @@ pub(crate) struct WorkflowMachines {
|
|
|
75
81
|
/// kept because the lang side polls & completes for every workflow task, but we do not need
|
|
76
82
|
/// to poll the server that often during replay.
|
|
77
83
|
last_history_from_server: HistoryUpdate,
|
|
84
|
+
/// Protocol messages that have yet to be processed for the current WFT.
|
|
85
|
+
protocol_msgs: Vec<IncomingProtocolMessage>,
|
|
78
86
|
/// EventId of the last handled WorkflowTaskStarted event
|
|
79
87
|
current_started_event_id: i64,
|
|
80
88
|
/// The event id of the next workflow task started event that the machines need to process.
|
|
@@ -87,16 +95,12 @@ pub(crate) struct WorkflowMachines {
|
|
|
87
95
|
pub last_processed_event: i64,
|
|
88
96
|
/// True if the workflow is replaying from history
|
|
89
97
|
pub replaying: bool,
|
|
90
|
-
/// Namespace this workflow exists in
|
|
91
|
-
pub namespace: String,
|
|
92
98
|
/// Workflow identifier
|
|
93
99
|
pub workflow_id: String,
|
|
94
100
|
/// Workflow type identifier. (Function name, class, etc)
|
|
95
101
|
pub workflow_type: String,
|
|
96
102
|
/// Identifies the current run
|
|
97
103
|
pub run_id: String,
|
|
98
|
-
/// The task queue this workflow is operating within
|
|
99
|
-
pub task_queue: String,
|
|
100
104
|
/// Is set to true once we've seen the final event in workflow history, to avoid accidentally
|
|
101
105
|
/// re-applying the final workflow task.
|
|
102
106
|
pub have_seen_terminal_event: bool,
|
|
@@ -117,16 +121,19 @@ pub(crate) struct WorkflowMachines {
|
|
|
117
121
|
history_size_bytes: u64,
|
|
118
122
|
/// Set on each WFT started event
|
|
119
123
|
continue_as_new_suggested: bool,
|
|
124
|
+
/// Set if the current WFT is already complete and that completion event had a build id in it.
|
|
125
|
+
current_wft_build_id: Option<String>,
|
|
120
126
|
|
|
121
127
|
all_machines: SlotMap<MachineKey, Machines>,
|
|
122
128
|
/// If a machine key is in this map, that machine was created internally by core, not as a
|
|
123
129
|
/// command from lang.
|
|
124
130
|
machine_is_core_created: SparseSecondaryMap<MachineKey, ()>,
|
|
125
|
-
|
|
126
131
|
/// A mapping for accessing machines associated to a particular event, where the key is the id
|
|
127
132
|
/// of the initiating event for that machine.
|
|
128
133
|
machines_by_event_id: HashMap<i64, MachineKey>,
|
|
129
|
-
|
|
134
|
+
/// A mapping for accessing machines that were created as a result of protocol messages. The
|
|
135
|
+
/// key is the protocol's instance id.
|
|
136
|
+
machines_by_protocol_instance_id: HashMap<String, MachineKey>,
|
|
130
137
|
/// Maps command ids as created by workflow authors to their associated machines.
|
|
131
138
|
id_to_machine: HashMap<CommandID, MachineKey>,
|
|
132
139
|
|
|
@@ -136,6 +143,9 @@ pub(crate) struct WorkflowMachines {
|
|
|
136
143
|
/// Commands generated by the currently processing workflow task, which will eventually be
|
|
137
144
|
/// transferred to `commands` (and hence eventually sent to the server)
|
|
138
145
|
current_wf_task_commands: VecDeque<CommandAndMachine>,
|
|
146
|
+
/// Messages generated while processing the current workflow task, which will be sent in the
|
|
147
|
+
/// next WFT response. Keyed by message id.
|
|
148
|
+
message_outbox: VecDeque<ProtocolMessage>,
|
|
139
149
|
|
|
140
150
|
/// Information about patch markers we have already seen while replaying history
|
|
141
151
|
encountered_patch_markers: HashMap<String, ChangeInfo>,
|
|
@@ -148,6 +158,7 @@ pub(crate) struct WorkflowMachines {
|
|
|
148
158
|
|
|
149
159
|
/// Metrics context
|
|
150
160
|
pub metrics: MetricsContext,
|
|
161
|
+
worker_config: Arc<WorkerConfig>,
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
#[derive(Debug, derive_more::Display)]
|
|
@@ -180,6 +191,9 @@ pub(super) enum MachineResponse {
|
|
|
180
191
|
/// Pushes a new command into the list that will be sent to server once we respond with the
|
|
181
192
|
/// workflow task completion
|
|
182
193
|
IssueNewCommand(ProtoCommand),
|
|
194
|
+
/// Pushes a new protocol message into the list that will be sent to server once we respond with
|
|
195
|
+
/// the workflow task completion
|
|
196
|
+
IssueNewMessage(ProtocolMessage),
|
|
183
197
|
/// The machine requests the creation of another *different* machine. This acts as if lang
|
|
184
198
|
/// had replied to the activation with a command, but we use a special set of IDs to avoid
|
|
185
199
|
/// collisions.
|
|
@@ -230,11 +244,10 @@ impl WorkflowMachines {
|
|
|
230
244
|
};
|
|
231
245
|
Self {
|
|
232
246
|
last_history_from_server: basics.history,
|
|
233
|
-
|
|
247
|
+
protocol_msgs: vec![],
|
|
234
248
|
workflow_id: basics.workflow_id,
|
|
235
249
|
workflow_type: basics.workflow_type,
|
|
236
250
|
run_id: basics.run_id,
|
|
237
|
-
task_queue: basics.task_queue,
|
|
238
251
|
drive_me: driven_wf,
|
|
239
252
|
replaying,
|
|
240
253
|
metrics: basics.metrics,
|
|
@@ -249,15 +262,19 @@ impl WorkflowMachines {
|
|
|
249
262
|
observed_internal_flags: Rc::new(RefCell::new(observed_internal_flags)),
|
|
250
263
|
history_size_bytes: 0,
|
|
251
264
|
continue_as_new_suggested: false,
|
|
265
|
+
current_wft_build_id: None,
|
|
252
266
|
all_machines: Default::default(),
|
|
253
267
|
machine_is_core_created: Default::default(),
|
|
254
268
|
machines_by_event_id: Default::default(),
|
|
269
|
+
machines_by_protocol_instance_id: Default::default(),
|
|
255
270
|
id_to_machine: Default::default(),
|
|
256
271
|
commands: Default::default(),
|
|
257
272
|
current_wf_task_commands: Default::default(),
|
|
273
|
+
message_outbox: Default::default(),
|
|
258
274
|
encountered_patch_markers: Default::default(),
|
|
259
275
|
local_activity_data: LocalActivityData::default(),
|
|
260
276
|
have_seen_terminal_event: false,
|
|
277
|
+
worker_config: basics.worker_config,
|
|
261
278
|
}
|
|
262
279
|
}
|
|
263
280
|
|
|
@@ -274,6 +291,20 @@ impl WorkflowMachines {
|
|
|
274
291
|
.and_then(|(st, et)| et.duration_since(st).ok())
|
|
275
292
|
}
|
|
276
293
|
|
|
294
|
+
/// Must be called every time a new WFT is received
|
|
295
|
+
pub(crate) fn new_work_from_server(
|
|
296
|
+
&mut self,
|
|
297
|
+
update: HistoryUpdate,
|
|
298
|
+
protocol_messages: Vec<IncomingProtocolMessage>,
|
|
299
|
+
) -> Result<()> {
|
|
300
|
+
if !self.protocol_msgs.is_empty() {
|
|
301
|
+
dbg_panic!("There are unprocessed protocol messages while receiving new work");
|
|
302
|
+
}
|
|
303
|
+
self.protocol_msgs = protocol_messages;
|
|
304
|
+
self.new_history_from_server(update)?;
|
|
305
|
+
Ok(())
|
|
306
|
+
}
|
|
307
|
+
|
|
277
308
|
pub(crate) fn new_history_from_server(&mut self, update: HistoryUpdate) -> Result<()> {
|
|
278
309
|
self.last_history_from_server = update;
|
|
279
310
|
self.replaying = self.last_history_from_server.previous_wft_started_id > 0;
|
|
@@ -335,28 +366,40 @@ impl WorkflowMachines {
|
|
|
335
366
|
self.drive_me.get_started_info()
|
|
336
367
|
}
|
|
337
368
|
|
|
369
|
+
pub(crate) fn get_last_wft_started_id(&self) -> i64 {
|
|
370
|
+
self.current_started_event_id
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
pub(crate) fn prepare_for_wft_response(&mut self) -> MachinesWFTResponseContent {
|
|
374
|
+
MachinesWFTResponseContent {
|
|
375
|
+
replaying: self.replaying,
|
|
376
|
+
has_pending_jobs: self.has_pending_jobs(),
|
|
377
|
+
have_seen_terminal_event: self.have_seen_terminal_event,
|
|
378
|
+
have_pending_la_resolutions: self.has_pending_la_resolutions(),
|
|
379
|
+
last_processed_event: self.last_processed_event,
|
|
380
|
+
me: self,
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
338
384
|
/// Fetches commands which are ready for processing from the state machines, generally to be
|
|
339
385
|
/// sent off to the server. They are not removed from the internal queue, that happens when
|
|
340
386
|
/// corresponding history events from the server are being handled.
|
|
341
|
-
pub(crate) fn get_commands(&self) ->
|
|
387
|
+
pub(crate) fn get_commands(&self) -> impl Iterator<Item = ProtoCommand> + '_ {
|
|
342
388
|
// Since we're about to write a WFT, record any internal flags we know about which aren't
|
|
343
389
|
// already recorded.
|
|
344
390
|
(*self.observed_internal_flags)
|
|
345
391
|
.borrow_mut()
|
|
346
392
|
.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
|
|
393
|
+
self.commands.iter().filter_map(|c| {
|
|
394
|
+
if !self.machine(c.machine).is_final_state() {
|
|
395
|
+
match &c.command {
|
|
396
|
+
MachineAssociatedCommand::Real(cmd) => Some((**cmd).clone()),
|
|
397
|
+
MachineAssociatedCommand::FakeLocalActivityMarker(_) => None,
|
|
357
398
|
}
|
|
358
|
-
}
|
|
359
|
-
|
|
399
|
+
} else {
|
|
400
|
+
None
|
|
401
|
+
}
|
|
402
|
+
})
|
|
360
403
|
}
|
|
361
404
|
|
|
362
405
|
/// Returns the next activation that needs to be performed by the lang sdk. Things like unblock
|
|
@@ -375,9 +418,16 @@ impl WorkflowMachines {
|
|
|
375
418
|
Some(workflow_activation_job::Variant::QueryWorkflow(_))
|
|
376
419
|
)
|
|
377
420
|
});
|
|
421
|
+
let is_replaying = self.replaying || all_query;
|
|
422
|
+
let build_id_for_current_task = if is_replaying {
|
|
423
|
+
self.current_wft_build_id.clone().unwrap_or_default()
|
|
424
|
+
} else {
|
|
425
|
+
self.current_wft_build_id = Some(self.worker_config.worker_build_id.clone());
|
|
426
|
+
self.worker_config.worker_build_id.clone()
|
|
427
|
+
};
|
|
378
428
|
WorkflowActivation {
|
|
379
429
|
timestamp: self.current_wf_time.map(Into::into),
|
|
380
|
-
is_replaying
|
|
430
|
+
is_replaying,
|
|
381
431
|
run_id: self.run_id.clone(),
|
|
382
432
|
history_length: self.last_processed_event as u32,
|
|
383
433
|
jobs,
|
|
@@ -387,6 +437,7 @@ impl WorkflowMachines {
|
|
|
387
437
|
.collect(),
|
|
388
438
|
history_size_bytes: self.history_size_bytes,
|
|
389
439
|
continue_as_new_suggested: self.continue_as_new_suggested,
|
|
440
|
+
build_id_for_current_task,
|
|
390
441
|
}
|
|
391
442
|
}
|
|
392
443
|
|
|
@@ -401,7 +452,13 @@ impl WorkflowMachines {
|
|
|
401
452
|
.any(|v| v.is_la_resolution)
|
|
402
453
|
}
|
|
403
454
|
|
|
404
|
-
pub(crate) fn get_metadata_for_wft_complete(&self) -> WorkflowTaskCompletedMetadata {
|
|
455
|
+
pub(crate) fn get_metadata_for_wft_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
456
|
+
// If this worker has a build ID and we're completing the task, we want to say our ID is the
|
|
457
|
+
// current build ID, so that if we get a query before any new history, we properly can
|
|
458
|
+
// report that our ID was the one used for the completion.
|
|
459
|
+
if !self.worker_config.worker_build_id.is_empty() {
|
|
460
|
+
self.current_wft_build_id = Some(self.worker_config.worker_build_id.clone());
|
|
461
|
+
}
|
|
405
462
|
(*self.observed_internal_flags)
|
|
406
463
|
.borrow_mut()
|
|
407
464
|
.gather_for_wft_complete()
|
|
@@ -413,6 +470,30 @@ impl WorkflowMachines {
|
|
|
413
470
|
.add_lang_used(flags);
|
|
414
471
|
}
|
|
415
472
|
|
|
473
|
+
/// Undo a speculative workflow task by resetting to a certain WFT Started ID. This can happen
|
|
474
|
+
/// when an update request is rejected.
|
|
475
|
+
pub(crate) fn reset_last_started_id(&mut self, id: i64) {
|
|
476
|
+
debug!("Resetting back to event id {} due to speculative WFT", id);
|
|
477
|
+
self.current_started_event_id = id;
|
|
478
|
+
// This is pretty nasty to just + 1 like this, but, we know WFT complete always follows
|
|
479
|
+
// WFT started, which the id given to us to reset to must be, and we need to avoid
|
|
480
|
+
// re-applying the WFT Completed event, so we make sure to consider that processed
|
|
481
|
+
self.last_processed_event = id + 1;
|
|
482
|
+
// Then, we have to drop any state machines (which should only be one workflow task machine)
|
|
483
|
+
// we may have created when servicing the speculative task.
|
|
484
|
+
// Remove when https://github.com/rust-lang/rust/issues/59618 is stable
|
|
485
|
+
let remove_these: Vec<_> = self
|
|
486
|
+
.machines_by_event_id
|
|
487
|
+
.iter()
|
|
488
|
+
.filter(|(mid, _)| **mid > id)
|
|
489
|
+
.map(|(mid, mkey)| (*mid, *mkey))
|
|
490
|
+
.collect();
|
|
491
|
+
for (mid, mkey) in remove_these {
|
|
492
|
+
self.machines_by_event_id.remove(&mid);
|
|
493
|
+
self.all_machines.remove(mkey);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
416
497
|
/// Iterate the state machines, which consists of grabbing any pending outgoing commands from
|
|
417
498
|
/// the workflow code, handling them, and preparing them to be sent off to the server.
|
|
418
499
|
pub(crate) fn iterate_machines(&mut self) -> Result<()> {
|
|
@@ -446,22 +527,42 @@ impl WorkflowMachines {
|
|
|
446
527
|
return Ok(0);
|
|
447
528
|
}
|
|
448
529
|
|
|
449
|
-
fn
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
530
|
+
fn get_processable_messages(
|
|
531
|
+
me: &mut WorkflowMachines,
|
|
532
|
+
for_event_id: i64,
|
|
533
|
+
) -> Vec<IncomingProtocolMessage> {
|
|
534
|
+
// Another thing to replace when `drain_filter` exists
|
|
535
|
+
let mut ret = vec![];
|
|
536
|
+
me.protocol_msgs = std::mem::take(&mut me.protocol_msgs)
|
|
537
|
+
.into_iter()
|
|
538
|
+
.filter_map(|x| {
|
|
539
|
+
if x.processable_after_event_id()
|
|
540
|
+
.is_some_and(|eid| eid <= for_event_id)
|
|
541
|
+
{
|
|
542
|
+
ret.push(x);
|
|
543
|
+
None
|
|
544
|
+
} else {
|
|
545
|
+
Some(x)
|
|
546
|
+
}
|
|
547
|
+
})
|
|
548
|
+
.collect();
|
|
549
|
+
ret
|
|
459
550
|
}
|
|
460
551
|
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
552
|
+
// Peek to the next WFT complete and update ourselves with data we might need in it.
|
|
553
|
+
if let Some(next_complete) = self
|
|
554
|
+
.last_history_from_server
|
|
555
|
+
.peek_next_wft_completed(self.last_processed_event)
|
|
556
|
+
{
|
|
557
|
+
// We update the internal flags before applying the current task
|
|
558
|
+
(*self.observed_internal_flags)
|
|
559
|
+
.borrow_mut()
|
|
560
|
+
.add_from_complete(next_complete);
|
|
561
|
+
// Save this tasks' Build ID if it had one
|
|
562
|
+
if let Some(bid) = next_complete.worker_version.as_ref().map(|wv| &wv.build_id) {
|
|
563
|
+
self.current_wft_build_id = Some(bid.to_string());
|
|
564
|
+
}
|
|
565
|
+
}
|
|
465
566
|
|
|
466
567
|
let last_handled_wft_started_id = self.current_started_event_id;
|
|
467
568
|
let (events, has_final_event) = match self
|
|
@@ -499,14 +600,14 @@ impl WorkflowMachines {
|
|
|
499
600
|
let mut do_handle_event = true;
|
|
500
601
|
let mut history = events.into_iter().peekable();
|
|
501
602
|
while let Some(event) = history.next() {
|
|
502
|
-
|
|
603
|
+
let eid = event.event_id;
|
|
604
|
+
if eid != self.last_processed_event + 1 {
|
|
503
605
|
return Err(WFMachinesError::Fatal(format!(
|
|
504
606
|
"History is out of order. Last processed event: {}, event id: {}",
|
|
505
|
-
self.last_processed_event,
|
|
607
|
+
self.last_processed_event, eid
|
|
506
608
|
)));
|
|
507
609
|
}
|
|
508
610
|
let next_event = history.peek();
|
|
509
|
-
let eid = event.event_id;
|
|
510
611
|
|
|
511
612
|
// This definition of replaying here is that we are no longer replaying as soon as we
|
|
512
613
|
// see new events that have never been seen or produced by the SDK.
|
|
@@ -520,7 +621,7 @@ impl WorkflowMachines {
|
|
|
520
621
|
// them.
|
|
521
622
|
if self.replaying
|
|
522
623
|
&& has_final_event
|
|
523
|
-
&&
|
|
624
|
+
&& eid > self.last_history_from_server.previous_wft_started_id
|
|
524
625
|
&& event.event_type() != EventType::WorkflowTaskCompleted
|
|
525
626
|
&& !event.is_command_event()
|
|
526
627
|
{
|
|
@@ -528,6 +629,12 @@ impl WorkflowMachines {
|
|
|
528
629
|
self.replaying = false;
|
|
529
630
|
}
|
|
530
631
|
|
|
632
|
+
// Process any messages that should be processed before the event we're about to handle
|
|
633
|
+
let processable_msgs = get_processable_messages(self, eid - 1);
|
|
634
|
+
for msg in processable_msgs {
|
|
635
|
+
self.handle_protocol_message(msg)?;
|
|
636
|
+
}
|
|
637
|
+
|
|
531
638
|
if do_handle_event {
|
|
532
639
|
let eho = self.handle_event(
|
|
533
640
|
HistEventData {
|
|
@@ -551,9 +658,14 @@ impl WorkflowMachines {
|
|
|
551
658
|
self.last_processed_event = eid;
|
|
552
659
|
}
|
|
553
660
|
|
|
661
|
+
// Needed to delay mutation of self until after we've iterated over peeked events.
|
|
662
|
+
enum DelayedAction {
|
|
663
|
+
WakeLa(MachineKey, CompleteLocalActivityData),
|
|
664
|
+
ProtocolMessage(IncomingProtocolMessage),
|
|
665
|
+
}
|
|
666
|
+
let mut delayed_actions = vec![];
|
|
554
667
|
// Scan through to the next WFT, searching for any patch / la markers, so that we can
|
|
555
668
|
// pre-resolve them.
|
|
556
|
-
let mut wake_las = vec![];
|
|
557
669
|
for e in self
|
|
558
670
|
.last_history_from_server
|
|
559
671
|
.peek_next_wft_sequence(last_handled_wft_started_id)
|
|
@@ -575,7 +687,7 @@ impl WorkflowMachines {
|
|
|
575
687
|
if let Ok(mk) =
|
|
576
688
|
self.get_machine_key(CommandID::LocalActivity(la_dat.marker_dat.seq))
|
|
577
689
|
{
|
|
578
|
-
|
|
690
|
+
delayed_actions.push(DelayedAction::WakeLa(mk, la_dat));
|
|
579
691
|
} else {
|
|
580
692
|
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
581
693
|
}
|
|
@@ -584,22 +696,51 @@ impl WorkflowMachines {
|
|
|
584
696
|
"Local activity marker was unparsable: {e:?}"
|
|
585
697
|
)));
|
|
586
698
|
}
|
|
699
|
+
} else if let Some(
|
|
700
|
+
history_event::Attributes::WorkflowExecutionUpdateAcceptedEventAttributes(ref atts),
|
|
701
|
+
) = e.attributes
|
|
702
|
+
{
|
|
703
|
+
// If we see a workflow update accepted event, initialize the machine for it by
|
|
704
|
+
// pretending we received the message we would've under not-replay.
|
|
705
|
+
delayed_actions.push(DelayedAction::ProtocolMessage(IncomingProtocolMessage {
|
|
706
|
+
id: atts.accepted_request_message_id.clone(),
|
|
707
|
+
protocol_instance_id: atts.protocol_instance_id.clone(),
|
|
708
|
+
sequencing_id: Some(SequencingId::EventId(
|
|
709
|
+
atts.accepted_request_sequencing_event_id,
|
|
710
|
+
)),
|
|
711
|
+
body: IncomingProtocolMessageBody::UpdateRequest(
|
|
712
|
+
atts.accepted_request
|
|
713
|
+
.clone()
|
|
714
|
+
.ok_or_else(|| {
|
|
715
|
+
WFMachinesError::Fatal(
|
|
716
|
+
"Update accepted event must contain accepted request"
|
|
717
|
+
.to_string(),
|
|
718
|
+
)
|
|
719
|
+
})?
|
|
720
|
+
.try_into()?,
|
|
721
|
+
),
|
|
722
|
+
}));
|
|
587
723
|
}
|
|
588
724
|
}
|
|
589
|
-
for
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
let
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
725
|
+
for action in delayed_actions {
|
|
726
|
+
match action {
|
|
727
|
+
DelayedAction::WakeLa(mk, la_dat) => {
|
|
728
|
+
let mach = self.machine_mut(mk);
|
|
729
|
+
if let Machines::LocalActivityMachine(ref mut lam) = *mach {
|
|
730
|
+
if lam.will_accept_resolve_marker() {
|
|
731
|
+
let resps = lam.try_resolve_with_dat(la_dat.into())?;
|
|
732
|
+
self.process_machine_responses(mk, resps)?;
|
|
733
|
+
} else {
|
|
734
|
+
self.local_activity_data.insert_peeked_marker(la_dat);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
DelayedAction::ProtocolMessage(pm) => {
|
|
739
|
+
self.handle_protocol_message(pm)?;
|
|
597
740
|
}
|
|
598
741
|
}
|
|
599
742
|
}
|
|
600
743
|
|
|
601
|
-
update_internal_flags(self);
|
|
602
|
-
|
|
603
744
|
if !self.replaying {
|
|
604
745
|
self.metrics.wf_task_replay_latency(replay_start.elapsed());
|
|
605
746
|
}
|
|
@@ -665,27 +806,19 @@ impl WorkflowMachines {
|
|
|
665
806
|
}
|
|
666
807
|
|
|
667
808
|
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!(
|
|
809
|
+
let mkey = self
|
|
810
|
+
.machines_by_event_id
|
|
811
|
+
.get(&initial_cmd_id)
|
|
812
|
+
.ok_or_else(|| {
|
|
813
|
+
WFMachinesError::Nondeterminism(format!(
|
|
681
814
|
"During event handling, this event had an initial command ID but we \
|
|
682
|
-
|
|
683
|
-
))
|
|
684
|
-
}
|
|
685
|
-
|
|
815
|
+
could not find a matching command for it: {event:?}"
|
|
816
|
+
))
|
|
817
|
+
})?;
|
|
818
|
+
self.submachine_handle_event(*mkey, event_dat)?;
|
|
686
819
|
} else {
|
|
687
820
|
self.handle_non_stateful_event(event_dat)?;
|
|
688
|
-
}
|
|
821
|
+
};
|
|
689
822
|
|
|
690
823
|
Ok(EventHandlingOutcome::Normal)
|
|
691
824
|
}
|
|
@@ -769,10 +902,7 @@ impl WorkflowMachines {
|
|
|
769
902
|
}
|
|
770
903
|
|
|
771
904
|
fn handle_non_stateful_event(&mut self, event_dat: HistEventData) -> Result<()> {
|
|
772
|
-
trace!(
|
|
773
|
-
event = %event_dat.event,
|
|
774
|
-
"handling non-stateful event"
|
|
775
|
-
);
|
|
905
|
+
trace!(event = %event_dat.event, "handling non-stateful event");
|
|
776
906
|
let event_id = event_dat.event.event_id;
|
|
777
907
|
match EventType::from_i32(event_dat.event.event_type) {
|
|
778
908
|
Some(EventType::WorkflowExecutionStarted) => {
|
|
@@ -855,6 +985,42 @@ impl WorkflowMachines {
|
|
|
855
985
|
self.process_machine_responses(sm, machine_responses)?;
|
|
856
986
|
Ok(())
|
|
857
987
|
}
|
|
988
|
+
/// Handle a single protocol message delivered in a workflow task.
|
|
989
|
+
///
|
|
990
|
+
/// This function will attempt to apply the message to a corresponding state machine for the
|
|
991
|
+
/// appropriate protocol type, creating it if it does not exist.
|
|
992
|
+
///
|
|
993
|
+
/// On replay, protocol messages may be made up by looking ahead in history to see if there is
|
|
994
|
+
/// already an event corresponding to the result of some protocol message which would have
|
|
995
|
+
/// existed to create that result.
|
|
996
|
+
#[instrument(skip(self))]
|
|
997
|
+
fn handle_protocol_message(&mut self, message: IncomingProtocolMessage) -> Result<()> {
|
|
998
|
+
static SEQIDERR: &str = "Update request messages must contain an event sequencing id! \
|
|
999
|
+
This is a server bug.";
|
|
1000
|
+
|
|
1001
|
+
match message.body {
|
|
1002
|
+
IncomingProtocolMessageBody::UpdateRequest(ur) => {
|
|
1003
|
+
let seq_id = if let SequencingId::EventId(eid) = message
|
|
1004
|
+
.sequencing_id
|
|
1005
|
+
.ok_or_else(|| WFMachinesError::Fatal(SEQIDERR.to_string()))?
|
|
1006
|
+
{
|
|
1007
|
+
eid
|
|
1008
|
+
} else {
|
|
1009
|
+
return Err(WFMachinesError::Fatal(SEQIDERR.to_string()));
|
|
1010
|
+
};
|
|
1011
|
+
let um = UpdateMachine::init(
|
|
1012
|
+
message.id,
|
|
1013
|
+
message.protocol_instance_id.clone(),
|
|
1014
|
+
seq_id,
|
|
1015
|
+
ur,
|
|
1016
|
+
self.replaying,
|
|
1017
|
+
);
|
|
1018
|
+
let mk = self.add_new_protocol_machine(um.machine, message.protocol_instance_id);
|
|
1019
|
+
self.process_machine_responses(mk, vec![um.response])?;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
Ok(())
|
|
1023
|
+
}
|
|
858
1024
|
|
|
859
1025
|
/// Transfer commands from `current_wf_task_commands` to `commands`, so they may be sent off
|
|
860
1026
|
/// to the server. While doing so, [TemporalStateMachine::handle_command] is called on the
|
|
@@ -940,6 +1106,13 @@ impl WorkflowMachines {
|
|
|
940
1106
|
machine: smk,
|
|
941
1107
|
})
|
|
942
1108
|
}
|
|
1109
|
+
MachineResponse::IssueNewMessage(pm) => {
|
|
1110
|
+
// Messages shouldn't be sent back when replaying. This is true for update,
|
|
1111
|
+
// currently the only user of protocol messages. May eventually change.
|
|
1112
|
+
if !self.replaying {
|
|
1113
|
+
self.message_outbox.push_back(pm);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
943
1116
|
MachineResponse::NewCoreOriginatedCommand(attrs) => match attrs {
|
|
944
1117
|
ProtoCmdAttrs::RequestCancelExternalWorkflowExecutionCommandAttributes(
|
|
945
1118
|
attrs,
|
|
@@ -1206,7 +1379,7 @@ impl WorkflowMachines {
|
|
|
1206
1379
|
}
|
|
1207
1380
|
Some(cancel_we::Target::ChildWorkflowId(wfid)) => (
|
|
1208
1381
|
NamespacedWorkflowExecution {
|
|
1209
|
-
namespace: self.namespace.clone(),
|
|
1382
|
+
namespace: self.worker_config.namespace.clone(),
|
|
1210
1383
|
workflow_id: wfid,
|
|
1211
1384
|
run_id: "".to_string(),
|
|
1212
1385
|
},
|
|
@@ -1227,7 +1400,7 @@ impl WorkflowMachines {
|
|
|
1227
1400
|
WFCommand::SignalExternalWorkflow(attrs) => {
|
|
1228
1401
|
let seq = attrs.seq;
|
|
1229
1402
|
self.add_cmd_to_wf_task(
|
|
1230
|
-
new_external_signal(attrs, &self.namespace)?,
|
|
1403
|
+
new_external_signal(attrs, &self.worker_config.namespace)?,
|
|
1231
1404
|
CommandID::SignalExternal(seq).into(),
|
|
1232
1405
|
);
|
|
1233
1406
|
}
|
|
@@ -1244,6 +1417,20 @@ impl WorkflowMachines {
|
|
|
1244
1417
|
CommandIdKind::NeverResolves,
|
|
1245
1418
|
);
|
|
1246
1419
|
}
|
|
1420
|
+
WFCommand::UpdateResponse(ur) => {
|
|
1421
|
+
let m_key = self.get_machine_by_msg(&ur.protocol_instance_id)?;
|
|
1422
|
+
let mach = self.machine_mut(m_key);
|
|
1423
|
+
if let Machines::UpdateMachine(m) = mach {
|
|
1424
|
+
let resps = m.handle_response(ur)?;
|
|
1425
|
+
self.process_machine_responses(m_key, resps)?;
|
|
1426
|
+
} else {
|
|
1427
|
+
return Err(WFMachinesError::Nondeterminism(format!(
|
|
1428
|
+
"Tried to handle an update response for \
|
|
1429
|
+
update with instance id {} but it was not found!",
|
|
1430
|
+
&ur.protocol_instance_id
|
|
1431
|
+
)));
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1247
1434
|
WFCommand::NoCommandsFromLang => (),
|
|
1248
1435
|
}
|
|
1249
1436
|
}
|
|
@@ -1267,6 +1454,17 @@ impl WorkflowMachines {
|
|
|
1267
1454
|
})?)
|
|
1268
1455
|
}
|
|
1269
1456
|
|
|
1457
|
+
fn get_machine_by_msg(&self, protocol_instance_id: &str) -> Result<MachineKey> {
|
|
1458
|
+
Ok(*self
|
|
1459
|
+
.machines_by_protocol_instance_id
|
|
1460
|
+
.get(protocol_instance_id)
|
|
1461
|
+
.ok_or_else(|| {
|
|
1462
|
+
WFMachinesError::Fatal(format!(
|
|
1463
|
+
"Missing associated machine for protocol message {protocol_instance_id}"
|
|
1464
|
+
))
|
|
1465
|
+
})?)
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1270
1468
|
fn add_terminal_command(&mut self, machine: NewMachineWithCommand) {
|
|
1271
1469
|
let cwfm = self.add_new_command_machine(machine);
|
|
1272
1470
|
self.workflow_end_time = Some(SystemTime::now());
|
|
@@ -1299,18 +1497,18 @@ impl WorkflowMachines {
|
|
|
1299
1497
|
}
|
|
1300
1498
|
}
|
|
1301
1499
|
|
|
1500
|
+
fn add_new_protocol_machine(&mut self, machine: Machines, instance_id: String) -> MachineKey {
|
|
1501
|
+
let k = self.all_machines.insert(machine);
|
|
1502
|
+
self.machines_by_protocol_instance_id.insert(instance_id, k);
|
|
1503
|
+
k
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1302
1506
|
fn machine(&self, m: MachineKey) -> &Machines {
|
|
1303
|
-
self.all_machines
|
|
1304
|
-
.get(m)
|
|
1305
|
-
.expect("Machine must exist")
|
|
1306
|
-
.borrow()
|
|
1507
|
+
self.all_machines.get(m).expect("Machine must exist")
|
|
1307
1508
|
}
|
|
1308
1509
|
|
|
1309
1510
|
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()
|
|
1511
|
+
self.all_machines.get_mut(m).expect("Machine must exist")
|
|
1314
1512
|
}
|
|
1315
1513
|
|
|
1316
1514
|
fn augment_continue_as_new_with_current_values(
|
|
@@ -1349,12 +1547,38 @@ impl WorkflowMachines {
|
|
|
1349
1547
|
VersioningIntent::Unspecified => {
|
|
1350
1548
|
// If the target TQ is empty, that means use same TQ.
|
|
1351
1549
|
// When TQs match, use compat by default
|
|
1352
|
-
target_tq.is_empty() || target_tq == self.task_queue
|
|
1550
|
+
target_tq.is_empty() || target_tq == self.worker_config.task_queue
|
|
1353
1551
|
}
|
|
1354
1552
|
}
|
|
1355
1553
|
}
|
|
1356
1554
|
}
|
|
1357
1555
|
|
|
1556
|
+
/// Contains everything workflow machine internals need to bubble up when we're getting ready to
|
|
1557
|
+
/// respond with a WFT completion. Allows for lazy mutation of the machine, since mutation is not
|
|
1558
|
+
/// desired unless we are actually going to respond to the WFT, which may not always happen.
|
|
1559
|
+
pub struct MachinesWFTResponseContent<'a> {
|
|
1560
|
+
me: &'a mut WorkflowMachines,
|
|
1561
|
+
pub replaying: bool,
|
|
1562
|
+
pub has_pending_jobs: bool,
|
|
1563
|
+
pub have_seen_terminal_event: bool,
|
|
1564
|
+
pub have_pending_la_resolutions: bool,
|
|
1565
|
+
pub last_processed_event: i64,
|
|
1566
|
+
}
|
|
1567
|
+
impl<'a> MachinesWFTResponseContent<'a> {
|
|
1568
|
+
pub fn commands(&self) -> Peekable<impl Iterator<Item = ProtoCommand> + '_> {
|
|
1569
|
+
self.me.get_commands().peekable()
|
|
1570
|
+
}
|
|
1571
|
+
pub fn has_messages(&self) -> bool {
|
|
1572
|
+
!self.me.message_outbox.is_empty()
|
|
1573
|
+
}
|
|
1574
|
+
pub fn messages(&mut self) -> Vec<ProtocolMessage> {
|
|
1575
|
+
self.me.message_outbox.drain(..).collect()
|
|
1576
|
+
}
|
|
1577
|
+
pub fn metadata_for_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
1578
|
+
self.me.get_metadata_for_wft_complete()
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1358
1582
|
fn str_to_randomness_seed(run_id: &str) -> u64 {
|
|
1359
1583
|
// This was originally `DefaultHasher` but that is potentially unstable across Rust releases.
|
|
1360
1584
|
// This must forever be `SipHasher13` now or we risk breaking history compat.
|
|
@@ -1385,8 +1609,9 @@ fn patch_marker_handling(
|
|
|
1385
1609
|
fn skip_one_or_two_events(next_event: Option<&HistoryEvent>) -> Result<EventHandlingOutcome> {
|
|
1386
1610
|
// Also ignore the subsequent upsert event if present
|
|
1387
1611
|
let mut skip_next_event = false;
|
|
1388
|
-
if let Some(Attributes::UpsertWorkflowSearchAttributesEventAttributes(
|
|
1389
|
-
|
|
1612
|
+
if let Some(history_event::Attributes::UpsertWorkflowSearchAttributesEventAttributes(
|
|
1613
|
+
atts,
|
|
1614
|
+
)) = next_event.and_then(|ne| ne.attributes.as_ref())
|
|
1390
1615
|
{
|
|
1391
1616
|
if let Some(ref sa) = atts.search_attributes {
|
|
1392
1617
|
skip_next_event = sa.indexed_fields.contains_key(VERSION_SEARCH_ATTR_KEY);
|