@temporalio/core-bridge 0.19.2 → 0.20.2
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 +90 -157
- package/Cargo.toml +1 -0
- package/index.d.ts +11 -27
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.buildkite/docker/Dockerfile +1 -1
- package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
- package/sdk-core/.cargo/config.toml +1 -0
- package/sdk-core/CODEOWNERS +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
- package/sdk-core/bridge-ffi/src/lib.rs +311 -315
- package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
- package/sdk-core/client/Cargo.toml +13 -9
- package/sdk-core/client/LICENSE.txt +23 -0
- package/sdk-core/client/src/lib.rs +286 -174
- package/sdk-core/client/src/metrics.rs +86 -12
- package/sdk-core/client/src/raw.rs +566 -0
- package/sdk-core/client/src/retry.rs +137 -99
- package/sdk-core/core/Cargo.toml +15 -10
- package/sdk-core/core/LICENSE.txt +23 -0
- package/sdk-core/core/benches/workflow_replay.rs +79 -0
- package/sdk-core/core/src/abstractions.rs +38 -0
- package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
- package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
- package/sdk-core/core/src/core_tests/determinism.rs +24 -12
- package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
- package/sdk-core/core/src/core_tests/mod.rs +30 -43
- package/sdk-core/core/src/core_tests/queries.rs +82 -81
- package/sdk-core/core/src/core_tests/workers.rs +111 -296
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
- package/sdk-core/core/src/lib.rs +73 -318
- package/sdk-core/core/src/pollers/mod.rs +4 -6
- package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
- package/sdk-core/core/src/protosext/mod.rs +7 -10
- package/sdk-core/core/src/replay/mod.rs +11 -150
- package/sdk-core/core/src/telemetry/metrics.rs +35 -2
- package/sdk-core/core/src/telemetry/mod.rs +49 -16
- package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
- package/sdk-core/core/src/test_help/mod.rs +104 -170
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
- package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
- package/sdk-core/core/src/worker/activities.rs +23 -16
- package/sdk-core/core/src/worker/client/mocks.rs +86 -0
- package/sdk-core/core/src/worker/client.rs +209 -0
- package/sdk-core/core/src/worker/mod.rs +207 -108
- package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
- package/sdk-core/core/src/workflow/history_update.rs +107 -24
- package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
- package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
- package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
- package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
- package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
- package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
- package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
- package/sdk-core/core/src/workflow/mod.rs +13 -1
- package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
- package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
- package/sdk-core/core-api/Cargo.toml +9 -1
- package/sdk-core/core-api/LICENSE.txt +23 -0
- package/sdk-core/core-api/src/errors.rs +7 -38
- package/sdk-core/core-api/src/lib.rs +44 -52
- package/sdk-core/core-api/src/worker.rs +10 -2
- package/sdk-core/etc/deps.svg +127 -96
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
- package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
- package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
- package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
- package/sdk-core/sdk/Cargo.toml +16 -2
- package/sdk-core/sdk/LICENSE.txt +23 -0
- package/sdk-core/sdk/src/interceptors.rs +11 -0
- package/sdk-core/sdk/src/lib.rs +139 -151
- package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
- package/sdk-core/sdk/src/workflow_context.rs +36 -17
- package/sdk-core/sdk/src/workflow_future.rs +19 -25
- package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
- package/sdk-core/sdk-core-protos/build.rs +1 -0
- package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
- package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
- package/sdk-core/test-utils/Cargo.toml +3 -1
- package/sdk-core/test-utils/src/canned_histories.rs +27 -0
- package/sdk-core/test-utils/src/histfetch.rs +3 -3
- package/sdk-core/test-utils/src/lib.rs +223 -68
- package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
- package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
- package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
- package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
- package/sdk-core/tests/load_tests.rs +9 -6
- package/sdk-core/tests/main.rs +43 -10
- package/src/conversions.rs +7 -12
- package/src/lib.rs +322 -357
- package/sdk-core/client/src/mocks.rs +0 -167
- package/sdk-core/core/src/worker/dispatcher.rs +0 -171
- package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
package/sdk-core/sdk/src/lib.rs
CHANGED
|
@@ -1,41 +1,67 @@
|
|
|
1
1
|
#![warn(missing_docs)] // error if there are missing docs
|
|
2
2
|
|
|
3
|
-
//! This crate
|
|
4
|
-
//! like normal workflow code. It should only depend on things in the core crate that are already
|
|
5
|
-
//! publicly exposed.
|
|
3
|
+
//! This crate defines an alpha-stage Temporal Rust SDK.
|
|
6
4
|
//!
|
|
7
|
-
//!
|
|
5
|
+
//! Currently defining activities and running an activity-only worker is the most stable code.
|
|
6
|
+
//! Workflow definitions exist and running a workflow worker works, but the API is still very
|
|
7
|
+
//! unstable.
|
|
8
|
+
//!
|
|
9
|
+
//! An example of running an activity worker:
|
|
10
|
+
//! ```no_run
|
|
11
|
+
//! use std::{sync::Arc, str::FromStr};
|
|
12
|
+
//! use temporal_sdk::{sdk_client_options, Worker};
|
|
13
|
+
//! use temporal_sdk_core::{init_worker, Url};
|
|
14
|
+
//! use temporal_sdk_core_api::worker::{WorkerConfig, WorkerConfigBuilder};
|
|
15
|
+
//!
|
|
16
|
+
//! #[tokio::main]
|
|
17
|
+
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
18
|
+
//! let server_options = sdk_client_options(Url::from_str("http://localhost:7233")?).build()?;
|
|
19
|
+
//! let client = server_options.connect("my_namespace", None).await?;
|
|
20
|
+
//! let worker_config = WorkerConfigBuilder::default().build()?;
|
|
21
|
+
//! let core_worker = init_worker(worker_config, client);
|
|
22
|
+
//!
|
|
23
|
+
//! let mut worker = Worker::new_from_core(Arc::new(core_worker), "task_queue");
|
|
24
|
+
//! worker.register_activity(
|
|
25
|
+
//! "echo_activity",
|
|
26
|
+
//! |echo_me: String| async move { Ok(echo_me) },
|
|
27
|
+
//! );
|
|
28
|
+
//! worker.run().await?;
|
|
29
|
+
//! Ok(())
|
|
30
|
+
//! }
|
|
31
|
+
//! ```
|
|
8
32
|
|
|
9
33
|
#[macro_use]
|
|
10
34
|
extern crate tracing;
|
|
11
35
|
|
|
12
36
|
mod conversions;
|
|
37
|
+
pub mod interceptors;
|
|
13
38
|
mod payload_converter;
|
|
14
39
|
mod workflow_context;
|
|
15
40
|
mod workflow_future;
|
|
16
41
|
|
|
17
42
|
pub use workflow_context::{
|
|
18
43
|
ActivityOptions, CancellableFuture, ChildWorkflow, ChildWorkflowOptions, LocalActivityOptions,
|
|
19
|
-
WfContext,
|
|
44
|
+
Signal, SignalData, SignalWorkflowOptions, WfContext,
|
|
20
45
|
};
|
|
21
46
|
|
|
22
|
-
use crate::
|
|
47
|
+
use crate::{
|
|
48
|
+
interceptors::WorkerInterceptor,
|
|
49
|
+
workflow_context::{ChildWfCommon, PendingChildWorkflow},
|
|
50
|
+
};
|
|
23
51
|
use anyhow::{anyhow, bail};
|
|
24
52
|
use futures::{future::BoxFuture, stream::FuturesUnordered, FutureExt, StreamExt};
|
|
53
|
+
use once_cell::sync::OnceCell;
|
|
25
54
|
use std::{
|
|
26
55
|
collections::HashMap,
|
|
27
56
|
fmt::{Debug, Display, Formatter},
|
|
28
57
|
future::Future,
|
|
29
|
-
|
|
30
|
-
sync::{
|
|
31
|
-
atomic::{AtomicUsize, Ordering},
|
|
32
|
-
Arc,
|
|
33
|
-
},
|
|
34
|
-
time::Duration,
|
|
58
|
+
sync::Arc,
|
|
35
59
|
};
|
|
60
|
+
use temporal_client::ClientOptionsBuilder;
|
|
61
|
+
use temporal_sdk_core::Url;
|
|
36
62
|
use temporal_sdk_core_api::{
|
|
37
63
|
errors::{PollActivityError, PollWfError},
|
|
38
|
-
|
|
64
|
+
Worker as CoreWorker,
|
|
39
65
|
};
|
|
40
66
|
use temporal_sdk_core_protos::{
|
|
41
67
|
coresdk::{
|
|
@@ -64,22 +90,40 @@ use tokio::{
|
|
|
64
90
|
};
|
|
65
91
|
use tokio_util::sync::CancellationToken;
|
|
66
92
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
93
|
+
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
94
|
+
|
|
95
|
+
/// Returns a [ClientOptionsBuilder] with required fields set to appropriate values
|
|
96
|
+
/// for the Rust SDK.
|
|
97
|
+
pub fn sdk_client_options(url: impl Into<Url>) -> ClientOptionsBuilder {
|
|
98
|
+
let mut builder = ClientOptionsBuilder::default();
|
|
99
|
+
builder
|
|
100
|
+
.target_url(url)
|
|
101
|
+
.client_name("rust-sdk".to_string())
|
|
102
|
+
.client_version(VERSION.to_string())
|
|
103
|
+
.worker_binary_id(binary_id().to_string());
|
|
104
|
+
|
|
105
|
+
builder
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// A worker that can poll for and respond to workflow tasks by using [WorkflowFunction]s,
|
|
109
|
+
/// and activity tasks by using [ActivityFunction]s
|
|
110
|
+
pub struct Worker {
|
|
111
|
+
common: CommonWorker,
|
|
72
112
|
workflow_half: WorkflowHalf,
|
|
73
113
|
activity_half: ActivityHalf,
|
|
74
114
|
}
|
|
75
115
|
|
|
116
|
+
struct CommonWorker {
|
|
117
|
+
worker: Arc<dyn CoreWorker>,
|
|
118
|
+
task_queue: String,
|
|
119
|
+
worker_interceptor: Option<Box<dyn WorkerInterceptor>>,
|
|
120
|
+
}
|
|
121
|
+
|
|
76
122
|
struct WorkflowHalf {
|
|
77
123
|
/// Maps run id to the driver
|
|
78
124
|
workflows: HashMap<String, UnboundedSender<WorkflowActivation>>,
|
|
79
125
|
/// Maps workflow type to the function for executing workflow runs with that ID
|
|
80
126
|
workflow_fns: HashMap<String, WorkflowFunction>,
|
|
81
|
-
/// Number of live workflows
|
|
82
|
-
incomplete_workflows: Arc<AtomicUsize>,
|
|
83
127
|
/// Handles for each spawned workflow run are inserted here to be cleaned up when all runs
|
|
84
128
|
/// are finished
|
|
85
129
|
join_handles: FuturesUnordered<BoxFuture<'static, Result<WorkflowResult<()>, JoinError>>>,
|
|
@@ -91,17 +135,21 @@ struct ActivityHalf {
|
|
|
91
135
|
task_tokens_to_cancels: HashMap<TaskToken, CancellationToken>,
|
|
92
136
|
}
|
|
93
137
|
|
|
94
|
-
impl
|
|
95
|
-
|
|
96
|
-
|
|
138
|
+
impl Worker {
|
|
139
|
+
// pub fn new(cfg: WorkerConfig) -> Self {}
|
|
140
|
+
|
|
141
|
+
#[doc(hidden)]
|
|
142
|
+
/// Create a new rust worker from a core worker
|
|
143
|
+
pub fn new_from_core(worker: Arc<dyn CoreWorker>, task_queue: impl Into<String>) -> Self {
|
|
97
144
|
Self {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
145
|
+
common: CommonWorker {
|
|
146
|
+
worker,
|
|
147
|
+
task_queue: task_queue.into(),
|
|
148
|
+
worker_interceptor: None,
|
|
149
|
+
},
|
|
101
150
|
workflow_half: WorkflowHalf {
|
|
102
151
|
workflows: Default::default(),
|
|
103
152
|
workflow_fns: Default::default(),
|
|
104
|
-
incomplete_workflows: Arc::new(AtomicUsize::new(0)),
|
|
105
153
|
join_handles: FuturesUnordered::new(),
|
|
106
154
|
},
|
|
107
155
|
activity_half: ActivityHalf {
|
|
@@ -113,35 +161,14 @@ impl TestRustWorker {
|
|
|
113
161
|
|
|
114
162
|
/// Returns the task queue name this worker polls on
|
|
115
163
|
pub fn task_queue(&self) -> &str {
|
|
116
|
-
&self.task_queue
|
|
164
|
+
&self.common.task_queue
|
|
117
165
|
}
|
|
118
166
|
|
|
119
|
-
///
|
|
120
|
-
///
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
/// Returns the run id of the started workflow
|
|
125
|
-
pub async fn submit_wf(
|
|
126
|
-
&self,
|
|
127
|
-
workflow_id: impl Into<String>,
|
|
128
|
-
workflow_type: impl Into<String>,
|
|
129
|
-
input: Vec<Payload>,
|
|
130
|
-
) -> Result<String, tonic::Status> {
|
|
131
|
-
let res = self
|
|
132
|
-
.core
|
|
133
|
-
.server_gateway()
|
|
134
|
-
.start_workflow(
|
|
135
|
-
input,
|
|
136
|
-
self.task_queue.clone(),
|
|
137
|
-
workflow_id.into(),
|
|
138
|
-
workflow_type.into(),
|
|
139
|
-
self.task_timeout,
|
|
140
|
-
)
|
|
141
|
-
.await?;
|
|
142
|
-
|
|
143
|
-
self.incr_expected_run_count(1);
|
|
144
|
-
Ok(res.run_id)
|
|
167
|
+
/// Return a handle that can be used to initiate shutdown.
|
|
168
|
+
/// TODO: Doc better after shutdown changes
|
|
169
|
+
pub fn shutdown_handle(&self) -> impl Fn() {
|
|
170
|
+
let w = self.common.worker.clone();
|
|
171
|
+
move || w.initiate_shutdown()
|
|
145
172
|
}
|
|
146
173
|
|
|
147
174
|
/// Register a Workflow function to invoke when the Worker is asked to run a workflow of
|
|
@@ -171,34 +198,19 @@ impl TestRustWorker {
|
|
|
171
198
|
);
|
|
172
199
|
}
|
|
173
200
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// workflow tracking
|
|
178
|
-
/// Increment the expected Workflow run count on this Worker. The Worker tracks the run count
|
|
179
|
-
/// and will resolve `run_until_done` when it goes down to 0.
|
|
180
|
-
/// You do not have to increment if scheduled a Workflow with `submit_wf`.
|
|
181
|
-
pub fn incr_expected_run_count(&self, count: usize) {
|
|
182
|
-
self.workflow_half
|
|
183
|
-
.incomplete_workflows
|
|
184
|
-
.fetch_add(count, Ordering::SeqCst);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/// See [Self::run_until_done], except calls the provided callback just before performing core
|
|
188
|
-
/// shutdown.
|
|
189
|
-
pub async fn run_until_done_shutdown_hook(
|
|
190
|
-
&mut self,
|
|
191
|
-
before_shutdown: impl FnOnce(),
|
|
192
|
-
) -> Result<(), anyhow::Error> {
|
|
201
|
+
/// Runs the worker. Eventually resolves after the worker has been explicitly shut down,
|
|
202
|
+
/// or may return early with an error in the event of some unresolvable problem.
|
|
203
|
+
pub async fn run(&mut self) -> Result<(), anyhow::Error> {
|
|
193
204
|
let (shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
194
205
|
let pollers = async move {
|
|
195
|
-
let (
|
|
206
|
+
let (common, wf_half, act_half) = self.split_apart();
|
|
196
207
|
let (completions_tx, mut completions_rx) = unbounded_channel();
|
|
197
208
|
let (wf_poll_res, act_poll_res) = tokio::join!(
|
|
198
209
|
// Workflow polling loop
|
|
199
210
|
async {
|
|
200
211
|
loop {
|
|
201
|
-
|
|
212
|
+
info!("Polling");
|
|
213
|
+
let activation = match common.worker.poll_workflow_activation().await {
|
|
202
214
|
Err(PollWfError::ShutDown) => {
|
|
203
215
|
break Result::<_, anyhow::Error>::Ok(());
|
|
204
216
|
}
|
|
@@ -206,20 +218,13 @@ impl TestRustWorker {
|
|
|
206
218
|
};
|
|
207
219
|
wf_half
|
|
208
220
|
.workflow_activation_handler(
|
|
209
|
-
|
|
210
|
-
task_q,
|
|
221
|
+
common,
|
|
211
222
|
&shutdown_rx,
|
|
212
223
|
&completions_tx,
|
|
213
224
|
&mut completions_rx,
|
|
214
225
|
activation,
|
|
215
226
|
)
|
|
216
227
|
.await?;
|
|
217
|
-
if wf_half.incomplete_workflows.load(Ordering::SeqCst) == 0 {
|
|
218
|
-
// Die rebel scum - evict all workflows (which are complete now),
|
|
219
|
-
// and turn off activity polling.
|
|
220
|
-
let _ = shutdown_tx.send(true);
|
|
221
|
-
break Result::<_, anyhow::Error>::Ok(());
|
|
222
|
-
}
|
|
223
228
|
}
|
|
224
229
|
},
|
|
225
230
|
// Only poll on the activity queue if activity functions have been registered. This
|
|
@@ -229,11 +234,11 @@ impl TestRustWorker {
|
|
|
229
234
|
if !act_half.activity_fns.is_empty() {
|
|
230
235
|
loop {
|
|
231
236
|
tokio::select! {
|
|
232
|
-
activity =
|
|
237
|
+
activity = common.worker.poll_activity_task() => {
|
|
233
238
|
if matches!(activity, Err(PollActivityError::ShutDown)) {
|
|
234
239
|
break;
|
|
235
240
|
}
|
|
236
|
-
act_half.activity_task_handler(
|
|
241
|
+
act_half.activity_task_handler(common.worker.clone(),
|
|
237
242
|
activity?)?;
|
|
238
243
|
},
|
|
239
244
|
_ = shutdown_rx.changed() => { break }
|
|
@@ -250,36 +255,31 @@ impl TestRustWorker {
|
|
|
250
255
|
};
|
|
251
256
|
|
|
252
257
|
let myself = pollers.await?;
|
|
258
|
+
info!("Polling loop exited");
|
|
259
|
+
let _ = shutdown_tx.send(true);
|
|
253
260
|
while let Some(h) = myself.workflow_half.join_handles.next().await {
|
|
254
261
|
h??;
|
|
255
262
|
}
|
|
256
|
-
|
|
257
|
-
myself.core.shutdown().await;
|
|
263
|
+
myself.common.worker.shutdown().await;
|
|
258
264
|
myself.workflow_half.workflows.clear();
|
|
259
265
|
Ok(())
|
|
260
266
|
}
|
|
261
267
|
|
|
262
|
-
///
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
self.run_until_done_shutdown_hook(|| {}).await
|
|
268
|
+
/// Set a [WorkerInterceptor]
|
|
269
|
+
pub fn set_worker_interceptor(&mut self, interceptor: Box<dyn WorkerInterceptor>) {
|
|
270
|
+
self.common.worker_interceptor = Some(interceptor);
|
|
266
271
|
}
|
|
267
272
|
|
|
268
|
-
///
|
|
269
|
-
///
|
|
270
|
-
///
|
|
271
|
-
pub fn
|
|
272
|
-
|
|
273
|
-
RustWorkerSwappedCore {
|
|
274
|
-
old_core: Some(old_core),
|
|
275
|
-
worker: self,
|
|
276
|
-
}
|
|
273
|
+
/// Turns this rust worker into a new worker with all the same workflows and activities
|
|
274
|
+
/// registered, but with a new underlying core worker. Can be used to swap the worker for
|
|
275
|
+
/// a replay worker, change task queues, etc.
|
|
276
|
+
pub fn with_new_core_worker(&mut self, new_core_worker: Arc<dyn CoreWorker>) {
|
|
277
|
+
self.common.worker = new_core_worker;
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
fn split_apart(&mut self) -> (
|
|
280
|
+
fn split_apart(&mut self) -> (&mut CommonWorker, &mut WorkflowHalf, &mut ActivityHalf) {
|
|
280
281
|
(
|
|
281
|
-
self.
|
|
282
|
-
&self.task_queue,
|
|
282
|
+
&mut self.common,
|
|
283
283
|
&mut self.workflow_half,
|
|
284
284
|
&mut self.activity_half,
|
|
285
285
|
)
|
|
@@ -289,8 +289,7 @@ impl TestRustWorker {
|
|
|
289
289
|
impl WorkflowHalf {
|
|
290
290
|
async fn workflow_activation_handler(
|
|
291
291
|
&mut self,
|
|
292
|
-
|
|
293
|
-
task_queue: &str,
|
|
292
|
+
common: &CommonWorker,
|
|
294
293
|
shutdown_rx: &Receiver<bool>,
|
|
295
294
|
completions_tx: &UnboundedSender<WorkflowActivationCompletion>,
|
|
296
295
|
completions_rx: &mut UnboundedReceiver<WorkflowActivationCompletion>,
|
|
@@ -302,14 +301,15 @@ impl WorkflowHalf {
|
|
|
302
301
|
variant: Some(Variant::StartWorkflow(sw)),
|
|
303
302
|
}) = activation.jobs.get(0)
|
|
304
303
|
{
|
|
304
|
+
let workflow_type = &sw.workflow_type;
|
|
305
305
|
let wf_function = self
|
|
306
306
|
.workflow_fns
|
|
307
|
-
.get(
|
|
308
|
-
.ok_or_else(|| anyhow!("Workflow type not found"))?;
|
|
307
|
+
.get(workflow_type)
|
|
308
|
+
.ok_or_else(|| anyhow!("Workflow type {workflow_type} not found"))?;
|
|
309
309
|
|
|
310
310
|
let (wff, activations) = wf_function.start_workflow(
|
|
311
|
-
|
|
312
|
-
task_queue.
|
|
311
|
+
common.worker.get_config().namespace.clone(),
|
|
312
|
+
common.task_queue.clone(),
|
|
313
313
|
// NOTE: Don't clone args if this gets ported to be a non-test rust worker
|
|
314
314
|
sw.arguments.clone(),
|
|
315
315
|
completions_tx.clone(),
|
|
@@ -336,11 +336,13 @@ impl WorkflowHalf {
|
|
|
336
336
|
};
|
|
337
337
|
|
|
338
338
|
let completion = completions_rx.recv().await.expect("No workflows left?");
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
self.incomplete_workflows.fetch_sub(1, Ordering::SeqCst);
|
|
339
|
+
if let Some(ref i) = common.worker_interceptor {
|
|
340
|
+
i.on_workflow_activation_completion(&completion);
|
|
342
341
|
}
|
|
343
|
-
|
|
342
|
+
common
|
|
343
|
+
.worker
|
|
344
|
+
.complete_workflow_activation(completion)
|
|
345
|
+
.await?;
|
|
344
346
|
Ok(())
|
|
345
347
|
}
|
|
346
348
|
}
|
|
@@ -365,13 +367,11 @@ impl ActivityHalf {
|
|
|
365
367
|
/// Spawns off a task to handle the provided activity task
|
|
366
368
|
fn activity_task_handler(
|
|
367
369
|
&mut self,
|
|
368
|
-
|
|
369
|
-
task_queue: &str,
|
|
370
|
+
worker: Arc<dyn CoreWorker>,
|
|
370
371
|
activity: ActivityTask,
|
|
371
372
|
) -> Result<(), anyhow::Error> {
|
|
372
373
|
match activity.variant {
|
|
373
374
|
Some(activity_task::Variant::Start(start)) => {
|
|
374
|
-
let task_queue = task_queue.to_string();
|
|
375
375
|
let act_fn = self
|
|
376
376
|
.activity_fns
|
|
377
377
|
.get(&start.activity_type)
|
|
@@ -389,7 +389,7 @@ impl ActivityHalf {
|
|
|
389
389
|
tokio::spawn(ACT_CANCEL_TOK.scope(ct, async move {
|
|
390
390
|
let mut inputs = start.input;
|
|
391
391
|
let arg = inputs.pop().unwrap_or_default();
|
|
392
|
-
let output = (
|
|
392
|
+
let output = (act_fn.act_func)(arg).await;
|
|
393
393
|
let result = match output {
|
|
394
394
|
Ok(res) => ActivityExecutionResult::ok(res),
|
|
395
395
|
Err(err) => match err.downcast::<ActivityCancelledError>() {
|
|
@@ -397,12 +397,12 @@ impl ActivityHalf {
|
|
|
397
397
|
Err(other_err) => ActivityExecutionResult::fail(other_err.into()),
|
|
398
398
|
},
|
|
399
399
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
400
|
+
worker
|
|
401
|
+
.complete_activity_task(ActivityTaskCompletion {
|
|
402
|
+
task_token: activity.task_token,
|
|
403
|
+
result: Some(result),
|
|
404
|
+
})
|
|
405
|
+
.await?;
|
|
406
406
|
Result::<_, anyhow::Error>::Ok(())
|
|
407
407
|
}));
|
|
408
408
|
}
|
|
@@ -553,7 +553,7 @@ enum RustWfCmd {
|
|
|
553
553
|
NewCmd(CommandCreateRequest),
|
|
554
554
|
NewNonblockingCmd(workflow_command::Variant),
|
|
555
555
|
SubscribeChildWorkflowCompletion(CommandSubscribeChildWorkflowCompletion),
|
|
556
|
-
SubscribeSignal(String, UnboundedSender<
|
|
556
|
+
SubscribeSignal(String, UnboundedSender<SignalData>),
|
|
557
557
|
}
|
|
558
558
|
|
|
559
559
|
struct CommandCreateRequest {
|
|
@@ -669,31 +669,19 @@ where
|
|
|
669
669
|
}
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
-
///
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
688
|
-
self.worker
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
impl<'a> Drop for RustWorkerSwappedCore<'a> {
|
|
693
|
-
fn drop(&mut self) {
|
|
694
|
-
let _ = std::mem::replace(
|
|
695
|
-
&mut self.worker.core,
|
|
696
|
-
self.old_core.take().expect("Old core always exists"),
|
|
697
|
-
);
|
|
698
|
-
}
|
|
672
|
+
/// Reads own binary, hashes it, and returns b64 str version of that hash
|
|
673
|
+
fn binary_id() -> &'static str {
|
|
674
|
+
use sha2::{Digest, Sha256};
|
|
675
|
+
use std::{env, fs, io};
|
|
676
|
+
|
|
677
|
+
static INSTANCE: OnceCell<String> = OnceCell::new();
|
|
678
|
+
INSTANCE.get_or_init(|| {
|
|
679
|
+
let exe_path = env::current_exe().expect("Cannot read own binary to determine binary id");
|
|
680
|
+
let mut exe_file =
|
|
681
|
+
fs::File::open(exe_path).expect("Cannot read own binary to determine binary id");
|
|
682
|
+
let mut hasher = Sha256::new();
|
|
683
|
+
io::copy(&mut exe_file, &mut hasher).expect("Copying data into binary hasher works");
|
|
684
|
+
let hash = hasher.finalize();
|
|
685
|
+
base64::encode(hash)
|
|
686
|
+
})
|
|
699
687
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use std::time::Duration;
|
|
1
|
+
use std::{collections::HashMap, time::Duration};
|
|
2
2
|
use temporal_sdk_core_protos::coresdk::{
|
|
3
3
|
child_workflow::ChildWorkflowCancellationType,
|
|
4
4
|
common::{Payload, RetryPolicy},
|
|
@@ -178,3 +178,88 @@ impl IntoWorkflowCommand for ChildWorkflowOptions {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
+
|
|
182
|
+
/// Options for sending a signal to an external workflow
|
|
183
|
+
pub struct SignalWorkflowOptions {
|
|
184
|
+
/// The workflow's id
|
|
185
|
+
pub workflow_id: String,
|
|
186
|
+
/// The particular run to target, or latest if `None`
|
|
187
|
+
pub run_id: Option<String>,
|
|
188
|
+
/// The details of the signal to send
|
|
189
|
+
pub signal: Signal,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
impl SignalWorkflowOptions {
|
|
193
|
+
/// Create options for sending a signal to another workflow
|
|
194
|
+
pub fn new(
|
|
195
|
+
workflow_id: impl Into<String>,
|
|
196
|
+
run_id: impl Into<String>,
|
|
197
|
+
name: impl Into<String>,
|
|
198
|
+
input: impl IntoIterator<Item = impl Into<Payload>>,
|
|
199
|
+
) -> Self {
|
|
200
|
+
Self {
|
|
201
|
+
workflow_id: workflow_id.into(),
|
|
202
|
+
run_id: Some(run_id.into()),
|
|
203
|
+
signal: Signal::new(name, input),
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/// Set a header k/v pair attached to the signal
|
|
208
|
+
pub fn with_header(
|
|
209
|
+
&mut self,
|
|
210
|
+
key: impl Into<String>,
|
|
211
|
+
payload: impl Into<Payload>,
|
|
212
|
+
) -> &mut Self {
|
|
213
|
+
self.signal.data.with_header(key.into(), payload.into());
|
|
214
|
+
self
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/// Information needed to send a specific signal
|
|
219
|
+
pub struct Signal {
|
|
220
|
+
/// The signal name
|
|
221
|
+
pub signal_name: String,
|
|
222
|
+
/// The data the signal carries
|
|
223
|
+
pub data: SignalData,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
impl Signal {
|
|
227
|
+
/// Create a new signal
|
|
228
|
+
pub fn new(
|
|
229
|
+
name: impl Into<String>,
|
|
230
|
+
input: impl IntoIterator<Item = impl Into<Payload>>,
|
|
231
|
+
) -> Self {
|
|
232
|
+
Self {
|
|
233
|
+
signal_name: name.into(),
|
|
234
|
+
data: SignalData::new(input),
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/// Data contained within a signal
|
|
240
|
+
pub struct SignalData {
|
|
241
|
+
/// The arguments the signal will receive
|
|
242
|
+
pub input: Vec<Payload>,
|
|
243
|
+
/// Metadata attached to the signal
|
|
244
|
+
pub headers: HashMap<String, Payload>,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
impl SignalData {
|
|
248
|
+
/// Create data for a signal
|
|
249
|
+
pub fn new(input: impl IntoIterator<Item = impl Into<Payload>>) -> Self {
|
|
250
|
+
Self {
|
|
251
|
+
input: input.into_iter().map(Into::into).collect(),
|
|
252
|
+
headers: HashMap::new(),
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/// Set a header k/v pair attached to the signal
|
|
257
|
+
pub fn with_header(
|
|
258
|
+
&mut self,
|
|
259
|
+
key: impl Into<String>,
|
|
260
|
+
payload: impl Into<Payload>,
|
|
261
|
+
) -> &mut Self {
|
|
262
|
+
self.headers.insert(key.into(), payload.into());
|
|
263
|
+
self
|
|
264
|
+
}
|
|
265
|
+
}
|