@temporalio/core-bridge 0.16.4 → 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 +54 -54
- 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 +280 -292
- 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 +35 -83
- 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 +347 -221
- 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 +20 -31
- 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 +357 -171
- 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 +317 -103
- package/sdk-core/{test_utils → core-api}/Cargo.toml +10 -7
- package/sdk-core/{src → core-api/src}/errors.rs +42 -92
- 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 +601 -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 -157
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
//! This module is a rough prototype Rust SDK. It can be used to create closures that look sort of
|
|
2
|
-
//! like normal workflow code. It should only depend on things in the core crate that are already
|
|
3
|
-
//! publicly exposed.
|
|
4
|
-
//!
|
|
5
|
-
//! Needs lots of love to be production ready but the basis is there
|
|
6
|
-
|
|
7
|
-
mod conversions;
|
|
8
|
-
mod workflow_context;
|
|
9
|
-
mod workflow_future;
|
|
10
|
-
|
|
11
|
-
pub use workflow_context::{
|
|
12
|
-
ActivityOptions, CancellableFuture, ChildWorkflow, ChildWorkflowOptions, WfContext,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
use crate::{
|
|
16
|
-
prototype_rust_sdk::workflow_context::{ChildWfCommon, PendingChildWorkflow},
|
|
17
|
-
Core,
|
|
18
|
-
};
|
|
19
|
-
use anyhow::{anyhow, bail};
|
|
20
|
-
use futures::{future::BoxFuture, stream::FuturesUnordered, FutureExt, StreamExt};
|
|
21
|
-
use std::{
|
|
22
|
-
collections::HashMap,
|
|
23
|
-
fmt::Debug,
|
|
24
|
-
future::Future,
|
|
25
|
-
sync::{
|
|
26
|
-
atomic::{AtomicUsize, Ordering},
|
|
27
|
-
Arc,
|
|
28
|
-
},
|
|
29
|
-
time::Duration,
|
|
30
|
-
};
|
|
31
|
-
use temporal_sdk_core_protos::{
|
|
32
|
-
coresdk::{
|
|
33
|
-
activity_result::ActivityResult,
|
|
34
|
-
child_workflow::ChildWorkflowResult,
|
|
35
|
-
common::{NamespacedWorkflowExecution, Payload},
|
|
36
|
-
workflow_activation::{
|
|
37
|
-
resolve_child_workflow_execution_start::Status as ChildWorkflowStartStatus,
|
|
38
|
-
wf_activation_job::Variant, WfActivation, WfActivationJob,
|
|
39
|
-
},
|
|
40
|
-
workflow_commands::{workflow_command, ContinueAsNewWorkflowExecution},
|
|
41
|
-
},
|
|
42
|
-
temporal::api::failure::v1::Failure,
|
|
43
|
-
};
|
|
44
|
-
use tokio::{
|
|
45
|
-
sync::{
|
|
46
|
-
mpsc::{unbounded_channel, UnboundedSender},
|
|
47
|
-
oneshot, watch,
|
|
48
|
-
},
|
|
49
|
-
task::JoinError,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/// A worker that can poll for and respond to workflow tasks by using [WorkflowFunction]s
|
|
53
|
-
pub struct TestRustWorker {
|
|
54
|
-
core: Arc<dyn Core>,
|
|
55
|
-
task_queue: String,
|
|
56
|
-
task_timeout: Option<Duration>,
|
|
57
|
-
/// Maps run id to the driver
|
|
58
|
-
workflows: HashMap<String, UnboundedSender<WfActivation>>,
|
|
59
|
-
/// Maps workflow id to the function for executing workflow runs with that ID
|
|
60
|
-
workflow_fns: HashMap<String, WorkflowFunction>,
|
|
61
|
-
/// Number of live workflows
|
|
62
|
-
incomplete_workflows: Arc<AtomicUsize>,
|
|
63
|
-
/// Handles for each spawned workflow run are inserted here to be cleaned up when all runs
|
|
64
|
-
/// are finished
|
|
65
|
-
join_handles: FuturesUnordered<BoxFuture<'static, Result<WorkflowResult<()>, JoinError>>>,
|
|
66
|
-
}
|
|
67
|
-
type WfFunc = dyn Fn(WfContext) -> BoxFuture<'static, WorkflowResult<()>> + Send + Sync + 'static;
|
|
68
|
-
|
|
69
|
-
impl TestRustWorker {
|
|
70
|
-
/// Create a new rust worker
|
|
71
|
-
pub fn new(core: Arc<dyn Core>, task_queue: String, task_timeout: Option<Duration>) -> Self {
|
|
72
|
-
Self {
|
|
73
|
-
core,
|
|
74
|
-
task_queue,
|
|
75
|
-
task_timeout,
|
|
76
|
-
workflows: Default::default(),
|
|
77
|
-
workflow_fns: Default::default(),
|
|
78
|
-
incomplete_workflows: Arc::new(AtomicUsize::new(0)),
|
|
79
|
-
join_handles: FuturesUnordered::new(),
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/// Create a workflow, asking the server to start it with the provided workflow ID and using the
|
|
84
|
-
/// provided workflow function.
|
|
85
|
-
///
|
|
86
|
-
/// Increments the expected Workflow run count.
|
|
87
|
-
///
|
|
88
|
-
/// Returns the run id of the started workflow
|
|
89
|
-
pub async fn submit_wf(
|
|
90
|
-
&self,
|
|
91
|
-
workflow_id: impl Into<String>,
|
|
92
|
-
workflow_type: impl Into<String>,
|
|
93
|
-
input: Vec<Payload>,
|
|
94
|
-
) -> Result<String, tonic::Status> {
|
|
95
|
-
let res = self
|
|
96
|
-
.core
|
|
97
|
-
.server_gateway()
|
|
98
|
-
.start_workflow(
|
|
99
|
-
input,
|
|
100
|
-
self.task_queue.clone(),
|
|
101
|
-
workflow_id.into(),
|
|
102
|
-
workflow_type.into(),
|
|
103
|
-
self.task_timeout,
|
|
104
|
-
)
|
|
105
|
-
.await?;
|
|
106
|
-
|
|
107
|
-
self.incr_expected_run_count(1);
|
|
108
|
-
Ok(res.run_id)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/// Register a Workflow function to invoke when Worker is requested to run `workflow_type`
|
|
112
|
-
pub fn register_wf<F: Into<WorkflowFunction>>(
|
|
113
|
-
&mut self,
|
|
114
|
-
workflow_type: impl Into<String>,
|
|
115
|
-
wf_function: F,
|
|
116
|
-
) {
|
|
117
|
-
self.workflow_fns
|
|
118
|
-
.insert(workflow_type.into(), wf_function.into());
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/// Increment the expected Workflow run count on this Worker. The Worker tracks the run count
|
|
122
|
-
/// and will resolve `run_until_done` when it goes down to 0.
|
|
123
|
-
/// You do not have to increment if scheduled a Workflow with `submit_wf`.
|
|
124
|
-
pub fn incr_expected_run_count(&self, count: usize) {
|
|
125
|
-
self.incomplete_workflows.fetch_add(count, Ordering::SeqCst);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/// Drives all workflows until they have all finished, repeatedly polls server to fetch work
|
|
129
|
-
/// for them.
|
|
130
|
-
pub async fn run_until_done(mut self) -> Result<(), anyhow::Error> {
|
|
131
|
-
let (shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
132
|
-
let poller = async move {
|
|
133
|
-
let (completions_tx, mut completions_rx) = unbounded_channel();
|
|
134
|
-
loop {
|
|
135
|
-
let activation = self.core.poll_workflow_activation(&self.task_queue).await?;
|
|
136
|
-
|
|
137
|
-
// If the activation is to start a workflow, create a new workflow driver for it,
|
|
138
|
-
// using the function associated with that workflow id
|
|
139
|
-
if let Some(WfActivationJob {
|
|
140
|
-
variant: Some(Variant::StartWorkflow(sw)),
|
|
141
|
-
}) = activation.jobs.get(0)
|
|
142
|
-
{
|
|
143
|
-
let wf_function = self
|
|
144
|
-
.workflow_fns
|
|
145
|
-
.get(&sw.workflow_type)
|
|
146
|
-
.ok_or_else(|| anyhow!("Workflow type not found"))?;
|
|
147
|
-
|
|
148
|
-
let (wff, activations) = wf_function.start_workflow(
|
|
149
|
-
self.core.get_init_options().gateway_opts.namespace.clone(),
|
|
150
|
-
self.task_queue.clone(),
|
|
151
|
-
// NOTE: Don't clone args if this gets ported to be a non-test rust worker
|
|
152
|
-
sw.arguments.clone(),
|
|
153
|
-
completions_tx.clone(),
|
|
154
|
-
);
|
|
155
|
-
let mut shutdown_rx = shutdown_rx.clone();
|
|
156
|
-
let jh = tokio::spawn(async move {
|
|
157
|
-
tokio::select! {
|
|
158
|
-
r = wff => r,
|
|
159
|
-
_ = shutdown_rx.changed() => Ok(WfExitValue::Evicted)
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
self.workflows
|
|
163
|
-
.insert(activation.run_id.clone(), activations);
|
|
164
|
-
self.join_handles.push(jh.boxed());
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// The activation is expected to apply to some workflow we know about. Use it to
|
|
168
|
-
// unblock things and advance the workflow.
|
|
169
|
-
if let Some(tx) = self.workflows.get_mut(&activation.run_id) {
|
|
170
|
-
tx.send(activation)
|
|
171
|
-
.expect("Workflow should exist if we're sending it an activation");
|
|
172
|
-
} else {
|
|
173
|
-
bail!("Got activation for unknown workflow");
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
let completion = completions_rx.recv().await.expect("No workflows left?");
|
|
177
|
-
if completion.has_execution_ending() {
|
|
178
|
-
debug!("Workflow {} says it's finishing", &completion.run_id);
|
|
179
|
-
self.incomplete_workflows.fetch_sub(1, Ordering::SeqCst);
|
|
180
|
-
}
|
|
181
|
-
self.core.complete_workflow_activation(completion).await?;
|
|
182
|
-
if self.incomplete_workflows.load(Ordering::SeqCst) == 0 {
|
|
183
|
-
break Ok(self);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
let mut myself = poller.await?;
|
|
189
|
-
|
|
190
|
-
// Die rebel scum
|
|
191
|
-
let _ = shutdown_tx.send(true);
|
|
192
|
-
while let Some(h) = myself.join_handles.next().await {
|
|
193
|
-
h??;
|
|
194
|
-
}
|
|
195
|
-
Ok(())
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
#[derive(Debug)]
|
|
200
|
-
enum UnblockEvent {
|
|
201
|
-
Timer(u32),
|
|
202
|
-
Activity(u32, Box<ActivityResult>),
|
|
203
|
-
WorkflowStart(u32, Box<ChildWorkflowStartStatus>),
|
|
204
|
-
WorkflowComplete(u32, Box<ChildWorkflowResult>),
|
|
205
|
-
SignalExternal(u32, Option<Failure>),
|
|
206
|
-
CancelExternal(u32, Option<Failure>),
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/// Result of awaiting on a timer
|
|
210
|
-
pub struct TimerResult;
|
|
211
|
-
|
|
212
|
-
/// Successful result of sending a signal to an external workflow
|
|
213
|
-
pub struct SignalExternalOk;
|
|
214
|
-
/// Result of awaiting on sending a signal to an external workflow
|
|
215
|
-
pub type SignalExternalWfResult = Result<SignalExternalOk, Failure>;
|
|
216
|
-
|
|
217
|
-
/// Successful result of sending a cancel request to an external workflow
|
|
218
|
-
pub struct CancelExternalOk;
|
|
219
|
-
/// Result of awaiting on sending a cancel request to an external workflow
|
|
220
|
-
pub type CancelExternalWfResult = Result<CancelExternalOk, Failure>;
|
|
221
|
-
|
|
222
|
-
trait Unblockable {
|
|
223
|
-
type OtherDat;
|
|
224
|
-
|
|
225
|
-
fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
impl Unblockable for TimerResult {
|
|
229
|
-
type OtherDat = ();
|
|
230
|
-
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
|
231
|
-
match ue {
|
|
232
|
-
UnblockEvent::Timer(_) => TimerResult,
|
|
233
|
-
_ => panic!("Invalid unblock event for timer"),
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
impl Unblockable for ActivityResult {
|
|
239
|
-
type OtherDat = ();
|
|
240
|
-
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
|
241
|
-
match ue {
|
|
242
|
-
UnblockEvent::Activity(_, result) => *result,
|
|
243
|
-
_ => panic!("Invalid unblock event for activity"),
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
impl Unblockable for PendingChildWorkflow {
|
|
249
|
-
// Other data here is workflow id
|
|
250
|
-
type OtherDat = ChildWfCommon;
|
|
251
|
-
fn unblock(ue: UnblockEvent, od: Self::OtherDat) -> Self {
|
|
252
|
-
match ue {
|
|
253
|
-
UnblockEvent::WorkflowStart(_, result) => Self {
|
|
254
|
-
status: *result,
|
|
255
|
-
common: od,
|
|
256
|
-
},
|
|
257
|
-
_ => panic!("Invalid unblock event for child workflow start"),
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
impl Unblockable for ChildWorkflowResult {
|
|
263
|
-
type OtherDat = ();
|
|
264
|
-
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
|
265
|
-
match ue {
|
|
266
|
-
UnblockEvent::WorkflowComplete(_, result) => *result,
|
|
267
|
-
_ => panic!("Invalid unblock event for child workflow complete"),
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
impl Unblockable for SignalExternalWfResult {
|
|
273
|
-
type OtherDat = ();
|
|
274
|
-
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
|
275
|
-
match ue {
|
|
276
|
-
UnblockEvent::SignalExternal(_, maybefail) => {
|
|
277
|
-
maybefail.map_or(Ok(SignalExternalOk), Err)
|
|
278
|
-
}
|
|
279
|
-
_ => panic!("Invalid unblock event for signal external workflow result"),
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
impl Unblockable for CancelExternalWfResult {
|
|
285
|
-
type OtherDat = ();
|
|
286
|
-
fn unblock(ue: UnblockEvent, _: Self::OtherDat) -> Self {
|
|
287
|
-
match ue {
|
|
288
|
-
UnblockEvent::CancelExternal(_, maybefail) => {
|
|
289
|
-
maybefail.map_or(Ok(CancelExternalOk), Err)
|
|
290
|
-
}
|
|
291
|
-
_ => panic!("Invalid unblock event for signal external workflow result"),
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/// Identifier for cancellable operations
|
|
297
|
-
#[derive(Debug, Clone)]
|
|
298
|
-
pub enum CancellableID {
|
|
299
|
-
/// Timer sequence number
|
|
300
|
-
Timer(u32),
|
|
301
|
-
/// Activity sequence number
|
|
302
|
-
Activity(u32),
|
|
303
|
-
/// Start child sequence number
|
|
304
|
-
ChildWorkflow(u32),
|
|
305
|
-
/// Signal workflow
|
|
306
|
-
SignalExternalWorkflow(u32),
|
|
307
|
-
/// An external workflow identifier as may have been created by a started child workflow
|
|
308
|
-
ExternalWorkflow {
|
|
309
|
-
/// Sequence number which will be used for the cancel command
|
|
310
|
-
seqnum: u32,
|
|
311
|
-
/// Identifying information about the workflow to be cancelled
|
|
312
|
-
execution: NamespacedWorkflowExecution,
|
|
313
|
-
/// Set to true if this workflow is a child of the issuing workflow
|
|
314
|
-
only_child: bool,
|
|
315
|
-
},
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
#[derive(derive_more::From)]
|
|
319
|
-
#[allow(clippy::large_enum_variant)]
|
|
320
|
-
enum RustWfCmd {
|
|
321
|
-
#[from(ignore)]
|
|
322
|
-
Cancel(CancellableID),
|
|
323
|
-
ForceWFTFailure(anyhow::Error),
|
|
324
|
-
NewCmd(CommandCreateRequest),
|
|
325
|
-
NewNonblockingCmd(workflow_command::Variant),
|
|
326
|
-
SubscribeChildWorkflowCompletion(CommandSubscribeChildWorkflowCompletion),
|
|
327
|
-
SubscribeSignal(String, UnboundedSender<Vec<Payload>>),
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
struct CommandCreateRequest {
|
|
331
|
-
cmd: workflow_command::Variant,
|
|
332
|
-
unblocker: oneshot::Sender<UnblockEvent>,
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
struct CommandSubscribeChildWorkflowCompletion {
|
|
336
|
-
seq: u32,
|
|
337
|
-
unblocker: oneshot::Sender<UnblockEvent>,
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/// The user's async function / workflow code
|
|
341
|
-
pub struct WorkflowFunction {
|
|
342
|
-
wf_func: Box<WfFunc>,
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
impl<F, Fut> From<F> for WorkflowFunction
|
|
346
|
-
where
|
|
347
|
-
F: Fn(WfContext) -> Fut + Send + Sync + 'static,
|
|
348
|
-
Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
|
|
349
|
-
{
|
|
350
|
-
fn from(wf_func: F) -> Self {
|
|
351
|
-
Self::new(wf_func)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
impl WorkflowFunction {
|
|
356
|
-
/// Build a workflow function from a closure or function pointer which accepts a [WfContext]
|
|
357
|
-
pub fn new<F, Fut>(wf_func: F) -> Self
|
|
358
|
-
where
|
|
359
|
-
F: Fn(WfContext) -> Fut + Send + Sync + 'static,
|
|
360
|
-
Fut: Future<Output = WorkflowResult<()>> + Send + 'static,
|
|
361
|
-
{
|
|
362
|
-
Self {
|
|
363
|
-
wf_func: Box::new(move |ctx: WfContext| wf_func(ctx).boxed()),
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/// The result of running a workflow
|
|
369
|
-
pub type WorkflowResult<T> = Result<WfExitValue<T>, anyhow::Error>;
|
|
370
|
-
|
|
371
|
-
/// Workflow functions may return these values when exiting
|
|
372
|
-
#[derive(Debug, derive_more::From)]
|
|
373
|
-
pub enum WfExitValue<T: Debug> {
|
|
374
|
-
/// Continue the workflow as a new execution
|
|
375
|
-
#[from(ignore)]
|
|
376
|
-
ContinueAsNew(ContinueAsNewWorkflowExecution),
|
|
377
|
-
/// Confirm the workflow was cancelled (can be automatic in a more advanced iteration)
|
|
378
|
-
#[from(ignore)]
|
|
379
|
-
Cancelled,
|
|
380
|
-
/// The run was evicted
|
|
381
|
-
#[from(ignore)]
|
|
382
|
-
Evicted,
|
|
383
|
-
/// Finish with a result
|
|
384
|
-
Normal(T),
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
#[cfg(test)]
|
|
388
|
-
mod tests {
|
|
389
|
-
use super::*;
|
|
390
|
-
use crate::test_help::{build_fake_core, canned_histories, DEFAULT_WORKFLOW_TYPE, TEST_Q};
|
|
391
|
-
|
|
392
|
-
pub async fn timer_wf(mut ctx: WfContext) -> WorkflowResult<()> {
|
|
393
|
-
ctx.timer(Duration::from_secs(1)).await;
|
|
394
|
-
Ok(().into())
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
#[tokio::test]
|
|
398
|
-
async fn new_test_wf_core() {
|
|
399
|
-
let wf_id = "fakeid";
|
|
400
|
-
let wf_type = DEFAULT_WORKFLOW_TYPE;
|
|
401
|
-
let t = canned_histories::single_timer("1");
|
|
402
|
-
let core = build_fake_core(wf_id, t, [2]);
|
|
403
|
-
let mut worker = TestRustWorker::new(Arc::new(core), TEST_Q.to_string(), None);
|
|
404
|
-
|
|
405
|
-
worker.register_wf(wf_type.to_owned(), timer_wf);
|
|
406
|
-
worker
|
|
407
|
-
.submit_wf(wf_id.to_owned(), wf_type.to_owned(), vec![])
|
|
408
|
-
.await
|
|
409
|
-
.unwrap();
|
|
410
|
-
worker.run_until_done().await.unwrap();
|
|
411
|
-
}
|
|
412
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
use std::fmt::{Debug, Display, Formatter};
|
|
2
|
-
|
|
3
|
-
#[derive(Hash, Eq, PartialEq, Clone, derive_more::From, derive_more::Into)]
|
|
4
|
-
pub struct TaskToken(pub Vec<u8>);
|
|
5
|
-
|
|
6
|
-
impl Display for TaskToken {
|
|
7
|
-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
8
|
-
f.write_str(&fmt_tt(&self.0))
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
impl Debug for TaskToken {
|
|
13
|
-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
14
|
-
f.write_str(&format!("TaskToken({})", fmt_tt(&self.0)))
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub fn fmt_tt(tt: &[u8]) -> String {
|
|
19
|
-
base64::encode(tt)
|
|
20
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
use crate::workflow::HistoryUpdate;
|
|
2
|
-
use temporal_sdk_core_protos::temporal::api::{
|
|
3
|
-
enums::v1::EventType,
|
|
4
|
-
history::v1::{History, HistoryEvent},
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
#[derive(Clone, Debug, PartialEq)]
|
|
8
|
-
pub(crate) struct HistoryInfo {
|
|
9
|
-
pub previous_started_event_id: i64,
|
|
10
|
-
pub workflow_task_started_event_id: i64,
|
|
11
|
-
// This needs to stay private so the struct can't be instantiated outside of the constructor,
|
|
12
|
-
// which enforces some invariants regarding history structure that need to be upheld.
|
|
13
|
-
events: Vec<HistoryEvent>,
|
|
14
|
-
wf_task_count: usize,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type Result<T, E = HistoryInfoError> = std::result::Result<T, E>;
|
|
18
|
-
|
|
19
|
-
#[derive(thiserror::Error, Debug)]
|
|
20
|
-
#[allow(clippy::large_enum_variant)]
|
|
21
|
-
pub enum HistoryInfoError {
|
|
22
|
-
#[error("Latest wf started id and previous one are equal! ${previous_started_event_id:?}")]
|
|
23
|
-
UnexpectedEventId {
|
|
24
|
-
previous_started_event_id: i64,
|
|
25
|
-
workflow_task_started_event_id: i64,
|
|
26
|
-
},
|
|
27
|
-
#[error("Invalid history! Event {0:?} should be WF task completed, failed, or timed out")]
|
|
28
|
-
FailedOrTimeout(HistoryEvent),
|
|
29
|
-
#[error("Last item in history wasn't WorkflowTaskStarted")]
|
|
30
|
-
HistoryEndsUnexpectedly,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
impl HistoryInfo {
|
|
34
|
-
/// Constructs a new instance, retaining only enough events to reach the provided workflow
|
|
35
|
-
/// task number. If not provided, all events are retained.
|
|
36
|
-
pub(crate) fn new_from_history(h: &History, to_wf_task_num: Option<usize>) -> Result<Self> {
|
|
37
|
-
let events = &h.events;
|
|
38
|
-
if events.is_empty() {
|
|
39
|
-
return Err(HistoryInfoError::HistoryEndsUnexpectedly);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let to_wf_task_num = to_wf_task_num.unwrap_or(usize::MAX);
|
|
43
|
-
let mut workflow_task_started_event_id = 0;
|
|
44
|
-
let mut previous_started_event_id = 0;
|
|
45
|
-
let mut wf_task_count = 0;
|
|
46
|
-
let mut history = events.iter().peekable();
|
|
47
|
-
let mut events = vec![];
|
|
48
|
-
|
|
49
|
-
while let Some(event) = history.next() {
|
|
50
|
-
events.push(event.clone());
|
|
51
|
-
let next_event = history.peek();
|
|
52
|
-
|
|
53
|
-
if event.event_type == EventType::WorkflowTaskStarted as i32 {
|
|
54
|
-
let next_is_completed = next_event.map_or(false, |ne| {
|
|
55
|
-
ne.event_type == EventType::WorkflowTaskCompleted as i32
|
|
56
|
-
});
|
|
57
|
-
let next_is_failed_or_timeout = next_event.map_or(false, |ne| {
|
|
58
|
-
ne.event_type == EventType::WorkflowTaskFailed as i32
|
|
59
|
-
|| ne.event_type == EventType::WorkflowTaskTimedOut as i32
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if next_event.is_none() || next_is_completed {
|
|
63
|
-
previous_started_event_id = workflow_task_started_event_id;
|
|
64
|
-
workflow_task_started_event_id = event.event_id;
|
|
65
|
-
if workflow_task_started_event_id == previous_started_event_id {
|
|
66
|
-
return Err(HistoryInfoError::UnexpectedEventId {
|
|
67
|
-
previous_started_event_id,
|
|
68
|
-
workflow_task_started_event_id,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
wf_task_count += 1;
|
|
72
|
-
if wf_task_count == to_wf_task_num || next_event.is_none() {
|
|
73
|
-
return Ok(Self {
|
|
74
|
-
previous_started_event_id,
|
|
75
|
-
workflow_task_started_event_id,
|
|
76
|
-
events,
|
|
77
|
-
wf_task_count,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
} else if next_event.is_some() && !next_is_failed_or_timeout {
|
|
81
|
-
return Err(HistoryInfoError::FailedOrTimeout(event.clone()));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if next_event.is_none() {
|
|
86
|
-
if event.is_final_wf_execution_event() {
|
|
87
|
-
return Ok(Self {
|
|
88
|
-
previous_started_event_id,
|
|
89
|
-
workflow_task_started_event_id,
|
|
90
|
-
events,
|
|
91
|
-
wf_task_count,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
// No more events
|
|
95
|
-
if workflow_task_started_event_id != event.event_id {
|
|
96
|
-
return Err(HistoryInfoError::HistoryEndsUnexpectedly);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
unreachable!()
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/// Remove events from the beginning of this history such that it looks like what would've been
|
|
104
|
-
/// delivered on a sticky queue where the previously started task was the one before the last
|
|
105
|
-
/// task in this history.
|
|
106
|
-
pub(crate) fn make_incremental(&mut self) {
|
|
107
|
-
let last_complete_ix = self
|
|
108
|
-
.events
|
|
109
|
-
.iter()
|
|
110
|
-
.rposition(|he| he.event_type() == EventType::WorkflowTaskCompleted)
|
|
111
|
-
.expect("Must be a WFT completed event in history");
|
|
112
|
-
self.events.drain(0..=last_complete_ix);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
pub(crate) fn events(&self) -> &[HistoryEvent] {
|
|
116
|
-
&self.events
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/// Non-test code should *not* rely on just counting workflow tasks b/c of pagination
|
|
120
|
-
pub(crate) const fn wf_task_count(&self) -> usize {
|
|
121
|
-
self.wf_task_count
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
impl From<HistoryInfo> for HistoryUpdate {
|
|
126
|
-
fn from(v: HistoryInfo) -> Self {
|
|
127
|
-
Self::new_from_events(v.events, v.previous_started_event_id)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
impl From<HistoryInfo> for History {
|
|
132
|
-
fn from(i: HistoryInfo) -> Self {
|
|
133
|
-
Self { events: i.events }
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
#[cfg(test)]
|
|
138
|
-
mod tests {
|
|
139
|
-
use crate::test_help::canned_histories;
|
|
140
|
-
|
|
141
|
-
#[test]
|
|
142
|
-
fn history_info_constructs_properly() {
|
|
143
|
-
let t = canned_histories::single_timer("timer1");
|
|
144
|
-
|
|
145
|
-
let history_info = t.get_history_info(1).unwrap();
|
|
146
|
-
assert_eq!(3, history_info.events.len());
|
|
147
|
-
let history_info = t.get_history_info(2).unwrap();
|
|
148
|
-
assert_eq!(8, history_info.events.len());
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
#[test]
|
|
152
|
-
fn incremental_works() {
|
|
153
|
-
let t = canned_histories::single_timer("timer1");
|
|
154
|
-
let hi = t.get_one_wft(2).unwrap();
|
|
155
|
-
dbg!(hi.events);
|
|
156
|
-
}
|
|
157
|
-
}
|