@temporalio/core-bridge 0.17.2 → 0.18.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 +339 -226
- package/Cargo.toml +7 -3
- package/common.js +50 -0
- package/index.d.ts +7 -0
- package/index.js +12 -0
- package/package.json +7 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/{index.node → releases/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/scripts/build.js +10 -50
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +2 -2
- package/sdk-core/.buildkite/pipeline.yml +2 -0
- package/sdk-core/Cargo.toml +1 -88
- package/sdk-core/README.md +30 -6
- package/sdk-core/bridge-ffi/Cargo.toml +24 -0
- package/sdk-core/bridge-ffi/LICENSE.txt +23 -0
- package/sdk-core/bridge-ffi/build.rs +25 -0
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +216 -0
- package/sdk-core/bridge-ffi/src/lib.rs +829 -0
- package/sdk-core/bridge-ffi/src/wrappers.rs +193 -0
- package/sdk-core/client/Cargo.toml +32 -0
- package/sdk-core/{src/pollers/gateway.rs → client/src/lib.rs} +101 -195
- package/sdk-core/client/src/metrics.rs +89 -0
- package/sdk-core/client/src/mocks.rs +167 -0
- package/sdk-core/{src/pollers → client/src}/retry.rs +172 -14
- package/sdk-core/core/Cargo.toml +96 -0
- package/sdk-core/{src → core/src}/core_tests/activity_tasks.rs +193 -37
- package/sdk-core/{src → core/src}/core_tests/child_workflows.rs +14 -14
- package/sdk-core/{src → core/src}/core_tests/determinism.rs +8 -8
- package/sdk-core/core/src/core_tests/local_activities.rs +328 -0
- package/sdk-core/{src → core/src}/core_tests/mod.rs +6 -9
- package/sdk-core/{src → core/src}/core_tests/queries.rs +45 -52
- package/sdk-core/{src → core/src}/core_tests/replay_flag.rs +8 -12
- package/sdk-core/{src → core/src}/core_tests/workers.rs +120 -33
- package/sdk-core/{src → core/src}/core_tests/workflow_cancels.rs +16 -26
- package/sdk-core/{src → core/src}/core_tests/workflow_tasks.rs +264 -286
- package/sdk-core/core/src/lib.rs +374 -0
- package/sdk-core/{src → core/src}/log_export.rs +3 -27
- package/sdk-core/core/src/pending_activations.rs +162 -0
- package/sdk-core/{src → core/src}/pollers/mod.rs +4 -22
- package/sdk-core/{src → core/src}/pollers/poll_buffer.rs +1 -1
- package/sdk-core/core/src/protosext/mod.rs +396 -0
- package/sdk-core/core/src/replay/mod.rs +210 -0
- package/sdk-core/core/src/retry_logic.rs +144 -0
- package/sdk-core/{src → core/src}/telemetry/metrics.rs +3 -58
- package/sdk-core/{src → core/src}/telemetry/mod.rs +8 -8
- package/sdk-core/{src → core/src}/telemetry/prometheus_server.rs +0 -0
- package/sdk-core/{src → core/src}/test_help/mod.rs +34 -73
- package/sdk-core/{src → core/src}/worker/activities/activity_heartbeat_manager.rs +95 -42
- package/sdk-core/core/src/worker/activities/local_activities.rs +973 -0
- package/sdk-core/{src → core/src}/worker/activities.rs +52 -33
- package/sdk-core/{src → core/src}/worker/dispatcher.rs +8 -6
- package/sdk-core/{src → core/src}/worker/mod.rs +305 -195
- package/sdk-core/core/src/worker/wft_delivery.rs +81 -0
- package/sdk-core/{src → core/src}/workflow/bridge.rs +5 -2
- package/sdk-core/{src → core/src}/workflow/driven_workflow.rs +17 -7
- package/sdk-core/{src → core/src}/workflow/history_update.rs +33 -7
- package/sdk-core/{src → core/src/workflow}/machines/activity_state_machine.rs +26 -26
- package/sdk-core/{src → core/src/workflow}/machines/cancel_external_state_machine.rs +8 -11
- package/sdk-core/{src → core/src/workflow}/machines/cancel_workflow_state_machine.rs +19 -21
- package/sdk-core/{src → core/src/workflow}/machines/child_workflow_state_machine.rs +19 -21
- package/sdk-core/{src → core/src/workflow}/machines/complete_workflow_state_machine.rs +3 -5
- package/sdk-core/{src → core/src/workflow}/machines/continue_as_new_workflow_state_machine.rs +18 -18
- package/sdk-core/{src → core/src/workflow}/machines/fail_workflow_state_machine.rs +5 -6
- package/sdk-core/core/src/workflow/machines/local_activity_state_machine.rs +1451 -0
- package/sdk-core/{src → core/src/workflow}/machines/mod.rs +54 -107
- package/sdk-core/{src → core/src/workflow}/machines/mutable_side_effect_state_machine.rs +0 -0
- package/sdk-core/{src → core/src/workflow}/machines/patch_state_machine.rs +29 -30
- package/sdk-core/{src → core/src/workflow}/machines/side_effect_state_machine.rs +0 -0
- package/sdk-core/{src → core/src/workflow}/machines/signal_external_state_machine.rs +17 -19
- package/sdk-core/{src → core/src/workflow}/machines/timer_state_machine.rs +20 -21
- package/sdk-core/{src → core/src/workflow}/machines/transition_coverage.rs +5 -2
- package/sdk-core/{src → core/src/workflow}/machines/upsert_search_attributes_state_machine.rs +0 -0
- package/sdk-core/core/src/workflow/machines/workflow_machines/local_acts.rs +96 -0
- package/sdk-core/{src → core/src/workflow}/machines/workflow_machines.rs +344 -160
- package/sdk-core/{src → core/src/workflow}/machines/workflow_task_state_machine.rs +1 -1
- package/sdk-core/{src → core/src}/workflow/mod.rs +200 -39
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/cache_manager.rs +0 -0
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/concurrency_manager.rs +38 -5
- package/sdk-core/{src → core/src}/workflow/workflow_tasks/mod.rs +297 -81
- package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
- package/sdk-core/{src → core-api/src}/errors.rs +42 -90
- package/sdk-core/core-api/src/lib.rs +158 -0
- package/sdk-core/{src/worker/config.rs → core-api/src/worker.rs} +18 -23
- package/sdk-core/etc/deps.svg +156 -0
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +5 -5
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +3 -5
- package/sdk-core/fsm/rustfsm_trait/src/lib.rs +7 -1
- package/sdk-core/histories/fail_wf_task.bin +0 -0
- package/sdk-core/histories/timer_workflow_history.bin +0 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +44 -13
- package/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +19 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +1 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +9 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +13 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +14 -7
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +176 -18
- package/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +156 -7
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +135 -104
- package/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
- package/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +78 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +205 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +61 -0
- package/sdk-core/protos/local/{child_workflow.proto → temporal/sdk/core/child_workflow/child_workflow.proto} +1 -1
- package/sdk-core/protos/local/{common.proto → temporal/sdk/core/common/common.proto} +5 -3
- package/sdk-core/protos/local/{core_interface.proto → temporal/sdk/core/core_interface.proto} +10 -10
- package/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
- package/sdk-core/protos/local/{workflow_activation.proto → temporal/sdk/core/workflow_activation/workflow_activation.proto} +35 -11
- package/sdk-core/protos/local/{workflow_commands.proto → temporal/sdk/core/workflow_commands/workflow_commands.proto} +55 -4
- package/sdk-core/protos/local/{workflow_completion.proto → temporal/sdk/core/workflow_completion/workflow_completion.proto} +3 -3
- package/sdk-core/sdk/Cargo.toml +32 -0
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/conversions.rs +0 -0
- package/sdk-core/sdk/src/lib.rs +699 -0
- package/sdk-core/sdk/src/payload_converter.rs +11 -0
- package/sdk-core/sdk/src/workflow_context/options.rs +180 -0
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_context.rs +201 -124
- package/sdk-core/{src/prototype_rust_sdk → sdk/src}/workflow_future.rs +63 -30
- package/sdk-core/sdk-core-protos/Cargo.toml +10 -0
- package/sdk-core/sdk-core-protos/build.rs +28 -6
- package/sdk-core/sdk-core-protos/src/constants.rs +7 -0
- package/sdk-core/{src/test_help → sdk-core-protos/src}/history_builder.rs +134 -49
- package/sdk-core/sdk-core-protos/src/history_info.rs +216 -0
- package/sdk-core/sdk-core-protos/src/lib.rs +594 -168
- package/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +32 -0
- package/sdk-core/{src/test_help → test-utils/src}/canned_histories.rs +59 -78
- package/sdk-core/test-utils/src/histfetch.rs +28 -0
- package/sdk-core/{test_utils → test-utils}/src/lib.rs +131 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +11 -7
- package/sdk-core/tests/integ_tests/polling_tests.rs +12 -11
- package/sdk-core/tests/integ_tests/queries_tests.rs +82 -78
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +91 -71
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +3 -4
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +2 -4
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -6
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +4 -6
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -4
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +496 -0
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +5 -8
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +125 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +7 -13
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +33 -5
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +12 -16
- package/sdk-core/tests/integ_tests/workflow_tests.rs +85 -82
- package/sdk-core/tests/load_tests.rs +6 -6
- package/sdk-core/tests/main.rs +2 -2
- package/src/conversions.rs +24 -21
- package/src/errors.rs +8 -0
- package/src/lib.rs +323 -211
- package/sdk-core/protos/local/activity_result.proto +0 -46
- package/sdk-core/protos/local/activity_task.proto +0 -66
- package/sdk-core/src/core_tests/retry.rs +0 -147
- package/sdk-core/src/lib.rs +0 -403
- package/sdk-core/src/machines/local_activity_state_machine.rs +0 -117
- package/sdk-core/src/pending_activations.rs +0 -249
- package/sdk-core/src/protosext/mod.rs +0 -160
- package/sdk-core/src/prototype_rust_sdk.rs +0 -412
- package/sdk-core/src/task_token.rs +0 -20
- package/sdk-core/src/test_help/history_info.rs +0 -158
|
@@ -1,31 +1,29 @@
|
|
|
1
|
+
pub(crate) mod workflow_tasks;
|
|
2
|
+
|
|
1
3
|
mod bridge;
|
|
2
4
|
mod driven_workflow;
|
|
3
5
|
mod history_update;
|
|
4
|
-
|
|
6
|
+
mod machines;
|
|
5
7
|
|
|
6
8
|
pub(crate) use bridge::WorkflowBridge;
|
|
7
9
|
pub(crate) use driven_workflow::{DrivenWorkflow, WorkflowFetcher};
|
|
8
10
|
pub(crate) use history_update::{HistoryPaginator, HistoryUpdate};
|
|
11
|
+
pub(crate) use machines::WFMachinesError;
|
|
9
12
|
|
|
10
13
|
use crate::{
|
|
11
|
-
machines::{ProtoCommand, WFCommand, WFMachinesError, WorkflowMachines},
|
|
12
14
|
telemetry::metrics::MetricsContext,
|
|
15
|
+
worker::{LocalActRequest, LocalActivityResolution},
|
|
16
|
+
};
|
|
17
|
+
use machines::WorkflowMachines;
|
|
18
|
+
use std::{result, sync::mpsc::Sender};
|
|
19
|
+
use temporal_sdk_core_protos::{
|
|
20
|
+
coresdk::{workflow_activation::WorkflowActivation, workflow_commands::*},
|
|
21
|
+
temporal::api::command::v1::Command as ProtoCommand,
|
|
13
22
|
};
|
|
14
|
-
use std::sync::mpsc::Sender;
|
|
15
|
-
use temporal_sdk_core_protos::coresdk::workflow_activation::WfActivation;
|
|
16
23
|
|
|
17
24
|
pub(crate) const LEGACY_QUERY_ID: &str = "legacy_query";
|
|
18
|
-
type Result<T, E = WFMachinesError> = std::result::Result<T, E>;
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
pub(crate) enum CommandID {
|
|
22
|
-
Timer(u32),
|
|
23
|
-
Activity(u32),
|
|
24
|
-
ChildWorkflowStart(u32),
|
|
25
|
-
ChildWorkflowComplete(u32),
|
|
26
|
-
SignalExternal(u32),
|
|
27
|
-
CancelExternal(u32),
|
|
28
|
-
}
|
|
26
|
+
type Result<T, E = WFMachinesError> = std::result::Result<T, E>;
|
|
29
27
|
|
|
30
28
|
/// Manages an instance of a [WorkflowMachines], which is not thread-safe, as well as other data
|
|
31
29
|
/// associated with that specific workflow run.
|
|
@@ -43,6 +41,7 @@ impl WorkflowManager {
|
|
|
43
41
|
history: HistoryUpdate,
|
|
44
42
|
namespace: String,
|
|
45
43
|
workflow_id: String,
|
|
44
|
+
workflow_type: String,
|
|
46
45
|
run_id: String,
|
|
47
46
|
metrics: MetricsContext,
|
|
48
47
|
) -> Self {
|
|
@@ -50,6 +49,7 @@ impl WorkflowManager {
|
|
|
50
49
|
let state_machines = WorkflowMachines::new(
|
|
51
50
|
namespace,
|
|
52
51
|
workflow_id,
|
|
52
|
+
workflow_type,
|
|
53
53
|
run_id,
|
|
54
54
|
history,
|
|
55
55
|
Box::new(wfb).into(),
|
|
@@ -76,6 +76,11 @@ pub struct OutgoingServerCommands {
|
|
|
76
76
|
pub replaying: bool,
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
#[derive(Debug)]
|
|
80
|
+
pub(crate) enum LocalResolution {
|
|
81
|
+
LocalActivity(LocalActivityResolution),
|
|
82
|
+
}
|
|
83
|
+
|
|
79
84
|
impl WorkflowManager {
|
|
80
85
|
/// Given history that was just obtained from the server, pipe it into this workflow's machines.
|
|
81
86
|
///
|
|
@@ -84,17 +89,23 @@ impl WorkflowManager {
|
|
|
84
89
|
pub async fn feed_history_from_server(
|
|
85
90
|
&mut self,
|
|
86
91
|
update: HistoryUpdate,
|
|
87
|
-
) -> Result<
|
|
92
|
+
) -> Result<WorkflowActivation> {
|
|
88
93
|
self.machines.new_history_from_server(update).await?;
|
|
89
94
|
self.get_next_activation().await
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
/// Let this workflow know that something we've been waiting locally on has resolved, like a
|
|
98
|
+
/// local activity or side effect
|
|
99
|
+
pub fn notify_of_local_result(&mut self, resolved: LocalResolution) -> Result<()> {
|
|
100
|
+
self.machines.local_resolution(resolved)
|
|
101
|
+
}
|
|
102
|
+
|
|
92
103
|
/// Fetch the next workflow activation for this workflow if one is required. Doing so will apply
|
|
93
104
|
/// the next unapplied workflow task if such a sequence exists in history we already know about.
|
|
94
105
|
///
|
|
95
106
|
/// Callers may also need to call [get_server_commands] after this to issue any pending commands
|
|
96
107
|
/// to the server.
|
|
97
|
-
pub async fn get_next_activation(&mut self) -> Result<
|
|
108
|
+
pub async fn get_next_activation(&mut self) -> Result<WorkflowActivation> {
|
|
98
109
|
// First check if there are already some pending jobs, which can be a result of replay.
|
|
99
110
|
let activation = self.machines.get_wf_activation();
|
|
100
111
|
if !activation.jobs.is_empty() {
|
|
@@ -105,15 +116,43 @@ impl WorkflowManager {
|
|
|
105
116
|
Ok(self.machines.get_wf_activation())
|
|
106
117
|
}
|
|
107
118
|
|
|
119
|
+
/// If there are no pending jobs for the workflow, apply the next workflow task and check
|
|
120
|
+
/// again if there are any jobs. Importantly, does not *drain* jobs.
|
|
121
|
+
///
|
|
122
|
+
/// Returns true if there are jobs (before or after applying the next WFT).
|
|
123
|
+
pub async fn apply_next_task_if_ready(&mut self) -> Result<bool> {
|
|
124
|
+
if self.machines.has_pending_jobs() {
|
|
125
|
+
return Ok(true);
|
|
126
|
+
}
|
|
127
|
+
loop {
|
|
128
|
+
let consumed_events = self.machines.apply_next_wft_from_history().await?;
|
|
129
|
+
|
|
130
|
+
if consumed_events == 0 || !self.machines.replaying || self.machines.has_pending_jobs()
|
|
131
|
+
{
|
|
132
|
+
// Keep applying tasks while there are events, we are still replaying, and there are
|
|
133
|
+
// no jobs
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
Ok(self.machines.has_pending_jobs())
|
|
138
|
+
}
|
|
139
|
+
|
|
108
140
|
/// Typically called after [get_next_activation], use this to retrieve commands to be sent to
|
|
109
|
-
/// the server which been generated by the machines
|
|
110
|
-
|
|
141
|
+
/// the server which have been generated by the machines. Does *not* drain those commands.
|
|
142
|
+
/// See [WorkflowMachines::get_commands].
|
|
143
|
+
pub fn get_server_commands(&mut self) -> OutgoingServerCommands {
|
|
111
144
|
OutgoingServerCommands {
|
|
112
145
|
commands: self.machines.get_commands(),
|
|
113
146
|
replaying: self.machines.replaying,
|
|
114
147
|
}
|
|
115
148
|
}
|
|
116
149
|
|
|
150
|
+
/// Remove and return all queued local activities. Once this is called, they need to be
|
|
151
|
+
/// dispatched for execution.
|
|
152
|
+
pub fn drain_queued_local_activities(&mut self) -> Vec<LocalActRequest> {
|
|
153
|
+
self.machines.drain_queued_local_activities()
|
|
154
|
+
}
|
|
155
|
+
|
|
117
156
|
/// Feed the workflow machines new commands issued by the executing workflow code, and iterate
|
|
118
157
|
/// the machines.
|
|
119
158
|
pub async fn push_commands(&mut self, cmds: Vec<WFCommand>) -> Result<()> {
|
|
@@ -146,20 +185,105 @@ pub(crate) enum WorkflowCachingPolicy {
|
|
|
146
185
|
AfterEveryReply,
|
|
147
186
|
}
|
|
148
187
|
|
|
188
|
+
#[derive(thiserror::Error, Debug, derive_more::From)]
|
|
189
|
+
#[error("Lang provided workflow command with empty variant")]
|
|
190
|
+
pub struct EmptyWorkflowCommandErr;
|
|
191
|
+
|
|
192
|
+
/// [DrivenWorkflow]s respond with these when called, to indicate what they want to do next.
|
|
193
|
+
/// EX: Create a new timer, complete the workflow, etc.
|
|
194
|
+
#[derive(Debug, derive_more::From, derive_more::Display)]
|
|
195
|
+
#[allow(clippy::large_enum_variant)]
|
|
196
|
+
pub enum WFCommand {
|
|
197
|
+
/// Returned when we need to wait for the lang sdk to send us something
|
|
198
|
+
NoCommandsFromLang,
|
|
199
|
+
AddActivity(ScheduleActivity),
|
|
200
|
+
AddLocalActivity(ScheduleLocalActivity),
|
|
201
|
+
RequestCancelActivity(RequestCancelActivity),
|
|
202
|
+
RequestCancelLocalActivity(RequestCancelLocalActivity),
|
|
203
|
+
AddTimer(StartTimer),
|
|
204
|
+
CancelTimer(CancelTimer),
|
|
205
|
+
CompleteWorkflow(CompleteWorkflowExecution),
|
|
206
|
+
FailWorkflow(FailWorkflowExecution),
|
|
207
|
+
QueryResponse(QueryResult),
|
|
208
|
+
ContinueAsNew(ContinueAsNewWorkflowExecution),
|
|
209
|
+
CancelWorkflow(CancelWorkflowExecution),
|
|
210
|
+
SetPatchMarker(SetPatchMarker),
|
|
211
|
+
AddChildWorkflow(StartChildWorkflowExecution),
|
|
212
|
+
CancelUnstartedChild(CancelUnstartedChildWorkflowExecution),
|
|
213
|
+
RequestCancelExternalWorkflow(RequestCancelExternalWorkflowExecution),
|
|
214
|
+
SignalExternalWorkflow(SignalExternalWorkflowExecution),
|
|
215
|
+
CancelSignalWorkflow(CancelSignalWorkflow),
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
impl TryFrom<WorkflowCommand> for WFCommand {
|
|
219
|
+
type Error = EmptyWorkflowCommandErr;
|
|
220
|
+
|
|
221
|
+
fn try_from(c: WorkflowCommand) -> result::Result<Self, Self::Error> {
|
|
222
|
+
match c.variant.ok_or(EmptyWorkflowCommandErr)? {
|
|
223
|
+
workflow_command::Variant::StartTimer(s) => Ok(Self::AddTimer(s)),
|
|
224
|
+
workflow_command::Variant::CancelTimer(s) => Ok(Self::CancelTimer(s)),
|
|
225
|
+
workflow_command::Variant::ScheduleActivity(s) => Ok(Self::AddActivity(s)),
|
|
226
|
+
workflow_command::Variant::RequestCancelActivity(s) => {
|
|
227
|
+
Ok(Self::RequestCancelActivity(s))
|
|
228
|
+
}
|
|
229
|
+
workflow_command::Variant::CompleteWorkflowExecution(c) => {
|
|
230
|
+
Ok(Self::CompleteWorkflow(c))
|
|
231
|
+
}
|
|
232
|
+
workflow_command::Variant::FailWorkflowExecution(s) => Ok(Self::FailWorkflow(s)),
|
|
233
|
+
workflow_command::Variant::RespondToQuery(s) => Ok(Self::QueryResponse(s)),
|
|
234
|
+
workflow_command::Variant::ContinueAsNewWorkflowExecution(s) => {
|
|
235
|
+
Ok(Self::ContinueAsNew(s))
|
|
236
|
+
}
|
|
237
|
+
workflow_command::Variant::CancelWorkflowExecution(s) => Ok(Self::CancelWorkflow(s)),
|
|
238
|
+
workflow_command::Variant::SetPatchMarker(s) => Ok(Self::SetPatchMarker(s)),
|
|
239
|
+
workflow_command::Variant::StartChildWorkflowExecution(s) => {
|
|
240
|
+
Ok(Self::AddChildWorkflow(s))
|
|
241
|
+
}
|
|
242
|
+
workflow_command::Variant::RequestCancelExternalWorkflowExecution(s) => {
|
|
243
|
+
Ok(Self::RequestCancelExternalWorkflow(s))
|
|
244
|
+
}
|
|
245
|
+
workflow_command::Variant::SignalExternalWorkflowExecution(s) => {
|
|
246
|
+
Ok(Self::SignalExternalWorkflow(s))
|
|
247
|
+
}
|
|
248
|
+
workflow_command::Variant::CancelSignalWorkflow(s) => Ok(Self::CancelSignalWorkflow(s)),
|
|
249
|
+
workflow_command::Variant::CancelUnstartedChildWorkflowExecution(s) => {
|
|
250
|
+
Ok(Self::CancelUnstartedChild(s))
|
|
251
|
+
}
|
|
252
|
+
workflow_command::Variant::ScheduleLocalActivity(s) => Ok(Self::AddLocalActivity(s)),
|
|
253
|
+
workflow_command::Variant::RequestCancelLocalActivity(s) => {
|
|
254
|
+
Ok(Self::RequestCancelLocalActivity(s))
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
|
261
|
+
enum CommandID {
|
|
262
|
+
Timer(u32),
|
|
263
|
+
Activity(u32),
|
|
264
|
+
LocalActivity(u32),
|
|
265
|
+
ChildWorkflowStart(u32),
|
|
266
|
+
SignalExternal(u32),
|
|
267
|
+
CancelExternal(u32),
|
|
268
|
+
}
|
|
269
|
+
|
|
149
270
|
#[cfg(test)]
|
|
150
271
|
pub mod managed_wf {
|
|
151
272
|
use super::*;
|
|
152
273
|
use crate::{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
workflow::WorkflowFetcher,
|
|
274
|
+
replay::TestHistoryBuilder,
|
|
275
|
+
test_help::TEST_Q,
|
|
276
|
+
workflow::{history_update::TestHBExt, WFCommand, WorkflowFetcher},
|
|
157
277
|
};
|
|
158
|
-
use std::convert::TryInto;
|
|
278
|
+
use std::{convert::TryInto, time::Duration};
|
|
279
|
+
use temporal_sdk::{WorkflowFunction, WorkflowResult};
|
|
159
280
|
use temporal_sdk_core_protos::coresdk::{
|
|
281
|
+
activity_result::ActivityExecutionResult,
|
|
160
282
|
common::Payload,
|
|
161
|
-
workflow_activation::create_evict_activation,
|
|
162
|
-
workflow_completion::{
|
|
283
|
+
workflow_activation::{create_evict_activation, remove_from_cache::EvictionReason},
|
|
284
|
+
workflow_completion::{
|
|
285
|
+
workflow_activation_completion::Status, WorkflowActivationCompletion,
|
|
286
|
+
},
|
|
163
287
|
};
|
|
164
288
|
use tokio::{
|
|
165
289
|
sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
|
@@ -167,13 +291,14 @@ pub mod managed_wf {
|
|
|
167
291
|
};
|
|
168
292
|
|
|
169
293
|
pub(crate) struct WFFutureDriver {
|
|
170
|
-
completions_rx: UnboundedReceiver<
|
|
294
|
+
completions_rx: UnboundedReceiver<WorkflowActivationCompletion>,
|
|
171
295
|
}
|
|
172
296
|
|
|
173
297
|
#[async_trait::async_trait]
|
|
174
298
|
impl WorkflowFetcher for WFFutureDriver {
|
|
175
299
|
async fn fetch_workflow_iteration_output(&mut self) -> Vec<WFCommand> {
|
|
176
300
|
if let Some(completion) = self.completions_rx.recv().await {
|
|
301
|
+
debug!("Managed wf completion: {}", completion);
|
|
177
302
|
completion
|
|
178
303
|
.status
|
|
179
304
|
.map(|s| match s {
|
|
@@ -195,7 +320,7 @@ pub mod managed_wf {
|
|
|
195
320
|
#[must_use]
|
|
196
321
|
pub struct ManagedWFFunc {
|
|
197
322
|
mgr: WorkflowManager,
|
|
198
|
-
activation_tx: UnboundedSender<
|
|
323
|
+
activation_tx: UnboundedSender<WorkflowActivation>,
|
|
199
324
|
future_handle: Option<JoinHandle<WorkflowResult<()>>>,
|
|
200
325
|
was_shutdown: bool,
|
|
201
326
|
}
|
|
@@ -222,6 +347,7 @@ pub mod managed_wf {
|
|
|
222
347
|
let state_machines = WorkflowMachines::new(
|
|
223
348
|
"test_namespace".to_string(),
|
|
224
349
|
"wfid".to_string(),
|
|
350
|
+
"wftype".to_string(),
|
|
225
351
|
"runid".to_string(),
|
|
226
352
|
hist,
|
|
227
353
|
Box::new(driver).into(),
|
|
@@ -236,33 +362,62 @@ pub mod managed_wf {
|
|
|
236
362
|
}
|
|
237
363
|
}
|
|
238
364
|
|
|
239
|
-
|
|
365
|
+
#[instrument(level = "debug", skip(self))]
|
|
366
|
+
pub(crate) async fn get_next_activation(&mut self) -> Result<WorkflowActivation> {
|
|
240
367
|
let res = self.mgr.get_next_activation().await?;
|
|
241
368
|
debug!("Managed wf next activation: {}", &res);
|
|
242
|
-
|
|
243
|
-
// Nothing to do here
|
|
244
|
-
return Ok(res);
|
|
245
|
-
}
|
|
246
|
-
self.push_activation_to_wf(res.clone()).await?;
|
|
369
|
+
self.push_activation_to_wf(&res).await?;
|
|
247
370
|
Ok(res)
|
|
248
371
|
}
|
|
249
372
|
|
|
250
373
|
/// Return outgoing server commands as of the last iteration
|
|
251
|
-
pub(crate)
|
|
374
|
+
pub(crate) fn get_server_commands(&mut self) -> OutgoingServerCommands {
|
|
252
375
|
self.mgr.get_server_commands()
|
|
253
376
|
}
|
|
254
377
|
|
|
378
|
+
pub(crate) fn drain_queued_local_activities(&mut self) -> Vec<LocalActRequest> {
|
|
379
|
+
self.mgr.drain_queued_local_activities()
|
|
380
|
+
}
|
|
381
|
+
|
|
255
382
|
/// Feed new history, as if received a new poll result. Returns new activation
|
|
256
|
-
|
|
383
|
+
#[instrument(level = "debug", skip(self, update))]
|
|
384
|
+
pub(crate) async fn new_history(
|
|
385
|
+
&mut self,
|
|
386
|
+
update: HistoryUpdate,
|
|
387
|
+
) -> Result<WorkflowActivation> {
|
|
257
388
|
let res = self.mgr.feed_history_from_server(update).await?;
|
|
258
|
-
self.push_activation_to_wf(res
|
|
389
|
+
self.push_activation_to_wf(&res).await?;
|
|
259
390
|
Ok(res)
|
|
260
391
|
}
|
|
261
392
|
|
|
393
|
+
/// Say a local activity completed (they always take 1 second in these tests)
|
|
394
|
+
pub(crate) fn complete_local_activity(
|
|
395
|
+
&mut self,
|
|
396
|
+
seq_num: u32,
|
|
397
|
+
result: ActivityExecutionResult,
|
|
398
|
+
) -> Result<()> {
|
|
399
|
+
self.mgr
|
|
400
|
+
.notify_of_local_result(LocalResolution::LocalActivity(LocalActivityResolution {
|
|
401
|
+
seq: seq_num,
|
|
402
|
+
// We accept normal execution results and do this conversion because there
|
|
403
|
+
// are more helpers for constructing them.
|
|
404
|
+
result: result
|
|
405
|
+
.status
|
|
406
|
+
.expect("LA result must have a status")
|
|
407
|
+
.try_into()
|
|
408
|
+
.expect("LA execution result must be a valid LA result"),
|
|
409
|
+
runtime: Duration::from_secs(1),
|
|
410
|
+
attempt: 1,
|
|
411
|
+
backoff: None,
|
|
412
|
+
// Tests at this level don't use the LA dispatcher, so this is irrelevant
|
|
413
|
+
original_schedule_time: None,
|
|
414
|
+
}))
|
|
415
|
+
}
|
|
416
|
+
|
|
262
417
|
/// During testing it can be useful to run through all activations to simulate replay
|
|
263
418
|
/// easily. Returns the last produced activation with jobs in it, or an activation with no
|
|
264
419
|
/// jobs if the first call had no jobs.
|
|
265
|
-
pub(crate) async fn process_all_activations(&mut self) -> Result<
|
|
420
|
+
pub(crate) async fn process_all_activations(&mut self) -> Result<WorkflowActivation> {
|
|
266
421
|
let mut last_act = self.get_next_activation().await?;
|
|
267
422
|
let mut next_act = self.get_next_activation().await?;
|
|
268
423
|
while !next_act.jobs.is_empty() {
|
|
@@ -278,13 +433,19 @@ pub mod managed_wf {
|
|
|
278
433
|
let _ = self.activation_tx.send(create_evict_activation(
|
|
279
434
|
"not actually important".to_string(),
|
|
280
435
|
"force shutdown".to_string(),
|
|
436
|
+
EvictionReason::Unspecified,
|
|
281
437
|
));
|
|
282
438
|
self.future_handle.take().unwrap().await.unwrap()
|
|
283
439
|
}
|
|
284
440
|
|
|
285
|
-
|
|
441
|
+
#[instrument(level = "debug", skip(self, res))]
|
|
442
|
+
async fn push_activation_to_wf(&mut self, res: &WorkflowActivation) -> Result<()> {
|
|
443
|
+
if res.jobs.is_empty() {
|
|
444
|
+
// Nothing to do here
|
|
445
|
+
return Ok(());
|
|
446
|
+
}
|
|
286
447
|
self.activation_tx
|
|
287
|
-
.send(res)
|
|
448
|
+
.send(res.clone())
|
|
288
449
|
.expect("Workflow should not be dropped if we are still sending activations");
|
|
289
450
|
self.mgr.machines.iterate_machines().await?;
|
|
290
451
|
Ok(())
|
|
File without changes
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
errors::WorkflowMissingError,
|
|
3
2
|
protosext::ValidPollWFTQResponse,
|
|
4
3
|
telemetry::metrics::{workflow_type, MetricsContext},
|
|
5
4
|
workflow::{
|
|
6
|
-
workflow_tasks::{OutstandingActivation, OutstandingTask},
|
|
5
|
+
workflow_tasks::{OutstandingActivation, OutstandingTask, WorkflowMissingError},
|
|
7
6
|
HistoryUpdate, Result, WFMachinesError, WorkflowManager,
|
|
8
7
|
},
|
|
9
8
|
};
|
|
@@ -14,7 +13,7 @@ use std::{
|
|
|
14
13
|
fmt::Debug,
|
|
15
14
|
ops::{Deref, DerefMut},
|
|
16
15
|
};
|
|
17
|
-
use temporal_sdk_core_protos::coresdk::workflow_activation::
|
|
16
|
+
use temporal_sdk_core_protos::coresdk::workflow_activation::WorkflowActivation;
|
|
18
17
|
|
|
19
18
|
/// Provides a thread-safe way to access workflow machines for specific workflow runs
|
|
20
19
|
pub(crate) struct WorkflowConcurrencyManager {
|
|
@@ -151,7 +150,23 @@ impl WorkflowConcurrencyManager {
|
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
/// Indicate it's finished and remove any outstanding workflow task associated with the run
|
|
154
|
-
pub fn complete_wft(
|
|
153
|
+
pub fn complete_wft(
|
|
154
|
+
&self,
|
|
155
|
+
run_id: &str,
|
|
156
|
+
send_wft_complete_to_srv: bool,
|
|
157
|
+
) -> Option<OutstandingTask> {
|
|
158
|
+
// If the WFT completion wasn't sent to the server, but we did see the final event, we still
|
|
159
|
+
// want to clear the workflow task. This can really only happen in replay testing, where we
|
|
160
|
+
// will generate poll responses with complete history but no attached query, and such a WFT
|
|
161
|
+
// would never really exist. The server wouldn't send a workflow task with nothing to do,
|
|
162
|
+
// but they are very useful for testing complete replay.
|
|
163
|
+
let saw_final = self
|
|
164
|
+
.access_sync(run_id, |wfm| wfm.machines.have_seen_terminal_event)
|
|
165
|
+
.unwrap_or_default();
|
|
166
|
+
if !saw_final && !send_wft_complete_to_srv {
|
|
167
|
+
return None;
|
|
168
|
+
}
|
|
169
|
+
|
|
155
170
|
let retme = if let Ok(ot) = self.get_task_mut(run_id).as_deref_mut() {
|
|
156
171
|
(*ot).take()
|
|
157
172
|
} else {
|
|
@@ -201,7 +216,7 @@ impl WorkflowConcurrencyManager {
|
|
|
201
216
|
namespace: &str,
|
|
202
217
|
wf_type: &str,
|
|
203
218
|
parent_metrics: &MetricsContext,
|
|
204
|
-
) -> Result<
|
|
219
|
+
) -> Result<WorkflowActivation> {
|
|
205
220
|
let span = debug_span!("create_or_update machines", %run_id);
|
|
206
221
|
|
|
207
222
|
if self.runs.read().contains_key(run_id) {
|
|
@@ -224,6 +239,7 @@ impl WorkflowConcurrencyManager {
|
|
|
224
239
|
history,
|
|
225
240
|
namespace.to_owned(),
|
|
226
241
|
workflow_id.to_owned(),
|
|
242
|
+
wf_type.to_owned(),
|
|
227
243
|
run_id.to_owned(),
|
|
228
244
|
metrics.clone(),
|
|
229
245
|
);
|
|
@@ -263,6 +279,23 @@ impl WorkflowConcurrencyManager {
|
|
|
263
279
|
res
|
|
264
280
|
}
|
|
265
281
|
|
|
282
|
+
pub fn access_sync<F, Fout>(
|
|
283
|
+
&self,
|
|
284
|
+
run_id: &str,
|
|
285
|
+
mutator: F,
|
|
286
|
+
) -> Result<Fout, WorkflowMissingError>
|
|
287
|
+
where
|
|
288
|
+
F: for<'a> FnOnce(&'a mut WorkflowManager) -> Fout,
|
|
289
|
+
Fout: Send + Debug,
|
|
290
|
+
{
|
|
291
|
+
let readlock = self.runs.read();
|
|
292
|
+
let m = readlock.get(run_id).ok_or_else(|| WorkflowMissingError {
|
|
293
|
+
run_id: run_id.to_string(),
|
|
294
|
+
})?;
|
|
295
|
+
let mut wfm_mutex = m.wfm.lock();
|
|
296
|
+
Ok(mutator(&mut wfm_mutex))
|
|
297
|
+
}
|
|
298
|
+
|
|
266
299
|
/// Remove the workflow with the provided run id from management
|
|
267
300
|
pub fn evict(&self, run_id: &str) -> Option<ValidPollWFTQResponse> {
|
|
268
301
|
let val = self.runs.write().remove(run_id);
|