@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/core/src/lib.rs
CHANGED
|
@@ -10,6 +10,7 @@ pub extern crate assert_matches;
|
|
|
10
10
|
#[macro_use]
|
|
11
11
|
extern crate tracing;
|
|
12
12
|
|
|
13
|
+
mod abstractions;
|
|
13
14
|
mod log_export;
|
|
14
15
|
mod pending_activations;
|
|
15
16
|
mod pollers;
|
|
@@ -29,50 +30,30 @@ mod test_help;
|
|
|
29
30
|
pub(crate) use temporal_sdk_core_api::errors;
|
|
30
31
|
|
|
31
32
|
pub use pollers::{
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
Client, ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryClient, RetryConfig,
|
|
34
|
+
TlsConfig, WorkflowClientTrait,
|
|
35
|
+
};
|
|
36
|
+
pub use telemetry::{
|
|
37
|
+
fetch_global_buffered_logs, telemetry_init, TelemetryOptions, TelemetryOptionsBuilder,
|
|
34
38
|
};
|
|
35
|
-
pub use telemetry::{TelemetryOptions, TelemetryOptionsBuilder};
|
|
36
39
|
pub use temporal_sdk_core_api as api;
|
|
37
40
|
pub use temporal_sdk_core_protos as protos;
|
|
38
41
|
pub use temporal_sdk_core_protos::TaskToken;
|
|
39
42
|
pub use url::Url;
|
|
40
|
-
pub use worker::{WorkerConfig, WorkerConfigBuilder};
|
|
43
|
+
pub use worker::{Worker, WorkerConfig, WorkerConfigBuilder};
|
|
41
44
|
|
|
42
45
|
use crate::{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
telemetry_init,
|
|
47
|
-
},
|
|
48
|
-
worker::{Worker, WorkerDispatcher},
|
|
49
|
-
};
|
|
50
|
-
use std::{
|
|
51
|
-
ops::Deref,
|
|
52
|
-
sync::{
|
|
53
|
-
atomic::{AtomicBool, Ordering},
|
|
54
|
-
Arc,
|
|
55
|
-
},
|
|
46
|
+
replay::mock_client_from_history,
|
|
47
|
+
telemetry::metrics::{MetricsContext, METRIC_METER},
|
|
48
|
+
worker::client::WorkerClientBag,
|
|
56
49
|
};
|
|
50
|
+
use std::sync::Arc;
|
|
51
|
+
use temporal_client::AnyClient;
|
|
57
52
|
use temporal_sdk_core_api::{
|
|
58
|
-
errors::{
|
|
59
|
-
|
|
60
|
-
WorkerRegistrationError,
|
|
61
|
-
},
|
|
62
|
-
Core, CoreLog,
|
|
63
|
-
};
|
|
64
|
-
use temporal_sdk_core_protos::{
|
|
65
|
-
coresdk::{
|
|
66
|
-
activity_task::ActivityTask,
|
|
67
|
-
workflow_activation::{remove_from_cache::EvictionReason, WorkflowActivation},
|
|
68
|
-
workflow_completion::WorkflowActivationCompletion,
|
|
69
|
-
ActivityHeartbeat, ActivityTaskCompletion,
|
|
70
|
-
},
|
|
71
|
-
temporal::api::history::v1::History,
|
|
53
|
+
errors::{CompleteActivityError, PollActivityError, PollWfError},
|
|
54
|
+
CoreLog, Worker as WorkerTrait,
|
|
72
55
|
};
|
|
73
|
-
|
|
74
|
-
#[cfg(test)]
|
|
75
|
-
use crate::test_help::MockWorker;
|
|
56
|
+
use temporal_sdk_core_protos::{coresdk::ActivityHeartbeat, temporal::api::history::v1::History};
|
|
76
57
|
|
|
77
58
|
lazy_static::lazy_static! {
|
|
78
59
|
/// A process-wide unique string, which will be different on every startup
|
|
@@ -81,294 +62,68 @@ lazy_static::lazy_static! {
|
|
|
81
62
|
};
|
|
82
63
|
}
|
|
83
64
|
|
|
84
|
-
///
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
/// Expects that a tokio runtime exists.
|
|
98
|
-
pub async fn init(opts: CoreInitOptions) -> Result<CoreSDK, CoreInitError> {
|
|
99
|
-
telemetry_init(&opts.telemetry_opts).map_err(CoreInitError::TelemetryInitError)?;
|
|
100
|
-
// Initialize server client
|
|
101
|
-
let server_gateway = opts.gateway_opts.connect(Some(&METRIC_METER)).await?;
|
|
102
|
-
|
|
103
|
-
Ok(CoreSDK::new(server_gateway, opts))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/// Initialize core using a provided gateway instance, which is typically a mock
|
|
107
|
-
pub fn init_mock_gateway<SG: ServerGatewayApis + Send + Sync + 'static>(
|
|
108
|
-
opts: CoreInitOptions,
|
|
109
|
-
server_gateway: SG,
|
|
110
|
-
) -> Result<CoreSDK, CoreInitError> {
|
|
111
|
-
telemetry_init(&opts.telemetry_opts).map_err(CoreInitError::TelemetryInitError)?;
|
|
112
|
-
Ok(CoreSDK::new(server_gateway, opts))
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/// Implements the [Core] trait
|
|
116
|
-
pub struct CoreSDK {
|
|
117
|
-
/// Options provided at initialization time
|
|
118
|
-
init_options: CoreInitOptions,
|
|
119
|
-
/// A client for interacting with the Temporal service.
|
|
120
|
-
server_gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
|
|
121
|
-
/// Controls access to workers
|
|
122
|
-
workers: WorkerDispatcher,
|
|
123
|
-
/// Has shutdown been called and all workers drained of tasks?
|
|
124
|
-
whole_core_shutdown: AtomicBool,
|
|
125
|
-
/// Top-level metrics context
|
|
126
|
-
metrics: MetricsContext,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
#[async_trait::async_trait]
|
|
130
|
-
impl Core for CoreSDK {
|
|
131
|
-
fn register_worker(&self, config: WorkerConfig) -> Result<(), WorkerRegistrationError> {
|
|
132
|
-
info!(
|
|
133
|
-
task_queue = config.task_queue.as_str(),
|
|
134
|
-
"Registering worker"
|
|
135
|
-
);
|
|
136
|
-
let sticky_q = self.get_sticky_q_name_for_worker(&config);
|
|
137
|
-
self.workers.new_worker(
|
|
138
|
-
config,
|
|
139
|
-
sticky_q,
|
|
140
|
-
self.server_gateway.clone(),
|
|
141
|
-
self.metrics.clone(),
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
#[instrument(level = "debug", skip(self), fields(run_id))]
|
|
146
|
-
async fn poll_workflow_activation(
|
|
147
|
-
&self,
|
|
148
|
-
task_queue: &str,
|
|
149
|
-
) -> Result<WorkflowActivation, PollWfError> {
|
|
150
|
-
let worker = self.worker(task_queue)?;
|
|
151
|
-
worker.next_workflow_activation().await
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
#[instrument(level = "debug", skip(self))]
|
|
155
|
-
async fn poll_activity_task(
|
|
156
|
-
&self,
|
|
157
|
-
task_queue: &str,
|
|
158
|
-
) -> Result<ActivityTask, PollActivityError> {
|
|
159
|
-
loop {
|
|
160
|
-
if self.whole_core_shutdown.load(Ordering::Relaxed) {
|
|
161
|
-
return Err(PollActivityError::ShutDown);
|
|
162
|
-
}
|
|
163
|
-
let worker = self.worker(task_queue)?;
|
|
164
|
-
match worker.activity_poll().await.transpose() {
|
|
165
|
-
Some(r) => break r,
|
|
166
|
-
None => {
|
|
167
|
-
tokio::task::yield_now().await;
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
#[instrument(level = "debug", skip(self, completion),
|
|
175
|
-
fields(completion=%&completion, run_id=%completion.run_id))]
|
|
176
|
-
async fn complete_workflow_activation(
|
|
177
|
-
&self,
|
|
178
|
-
completion: WorkflowActivationCompletion,
|
|
179
|
-
) -> Result<(), CompleteWfError> {
|
|
180
|
-
let worker = self.worker(&completion.task_queue)?;
|
|
181
|
-
worker.complete_workflow_activation(completion).await
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
#[instrument(level = "debug", skip(self))]
|
|
185
|
-
async fn complete_activity_task(
|
|
186
|
-
&self,
|
|
187
|
-
completion: ActivityTaskCompletion,
|
|
188
|
-
) -> Result<(), CompleteActivityError> {
|
|
189
|
-
let task_token = TaskToken(completion.task_token);
|
|
190
|
-
let status = if let Some(s) = completion.result.and_then(|r| r.status) {
|
|
191
|
-
s
|
|
192
|
-
} else {
|
|
193
|
-
return Err(CompleteActivityError::MalformedActivityCompletion {
|
|
194
|
-
reason: "Activity completion had empty result/status field".to_owned(),
|
|
195
|
-
completion: None,
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
let worker = self.worker(&completion.task_queue)?;
|
|
200
|
-
worker.complete_activity(task_token, status).await
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
fn record_activity_heartbeat(&self, details: ActivityHeartbeat) {
|
|
204
|
-
if let Ok(w) = self.worker(&details.task_queue) {
|
|
205
|
-
w.record_heartbeat(details);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
fn request_workflow_eviction(&self, task_queue: &str, run_id: &str) {
|
|
210
|
-
if let Ok(w) = self.worker(task_queue) {
|
|
211
|
-
w.request_wf_eviction(
|
|
212
|
-
run_id,
|
|
213
|
-
"Eviction explicitly requested by lang",
|
|
214
|
-
EvictionReason::LangRequested,
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
fn server_gateway(&self) -> Arc<dyn ServerGatewayApis + Send + Sync> {
|
|
220
|
-
self.server_gateway.clone()
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async fn shutdown(&self) {
|
|
224
|
-
self.workers.shutdown_all().await;
|
|
225
|
-
self.whole_core_shutdown.store(true, Ordering::Relaxed);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
async fn shutdown_worker(&self, task_queue: &str) {
|
|
229
|
-
self.workers.shutdown_one(task_queue).await;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
fn fetch_buffered_logs(&self) -> Vec<CoreLog> {
|
|
233
|
-
fetch_global_buffered_logs()
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
impl CoreSDK {
|
|
238
|
-
pub(crate) fn new<SG: ServerGatewayApis + Send + Sync + 'static>(
|
|
239
|
-
server_gateway: SG,
|
|
240
|
-
init_options: CoreInitOptions,
|
|
241
|
-
) -> Self {
|
|
242
|
-
let server_gateway = Arc::new(server_gateway);
|
|
243
|
-
let workers = WorkerDispatcher::default();
|
|
244
|
-
Self {
|
|
245
|
-
workers,
|
|
246
|
-
init_options,
|
|
247
|
-
whole_core_shutdown: AtomicBool::new(false),
|
|
248
|
-
metrics: MetricsContext::top_level(server_gateway.get_options().namespace.clone()),
|
|
249
|
-
server_gateway,
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/// Register a worker for replaying a specific history. The worker should use a unique task
|
|
254
|
-
/// queue name. It will auto-shutdown as soon as the history has finished being replayed. The
|
|
255
|
-
/// provided gateway should be a mock, and this should only be used for workflow testing
|
|
256
|
-
/// purposes.
|
|
257
|
-
pub fn register_replay_worker(
|
|
258
|
-
&self,
|
|
259
|
-
config: WorkerConfig,
|
|
260
|
-
gateway: Arc<dyn ServerGatewayApis + Send + Sync>,
|
|
261
|
-
history: &History,
|
|
262
|
-
) -> Result<(), anyhow::Error> {
|
|
263
|
-
info!(
|
|
264
|
-
task_queue = config.task_queue.as_str(),
|
|
265
|
-
"Registering replay worker"
|
|
266
|
-
);
|
|
267
|
-
// Could possibly just use mocked pollers here, but they'd need to be un-test-moded
|
|
268
|
-
let run_id = history.extract_run_id_from_start()?.to_string();
|
|
269
|
-
let last_event = history.last_event_id();
|
|
270
|
-
let tq = config.task_queue.clone();
|
|
271
|
-
let mut worker = Worker::new(config, None, gateway, self.metrics.clone());
|
|
272
|
-
worker.set_post_activate_hook(move |worker| {
|
|
273
|
-
if worker
|
|
274
|
-
.wft_manager
|
|
275
|
-
.most_recently_processed_event(&run_id)
|
|
276
|
-
.unwrap_or_default()
|
|
277
|
-
>= last_event
|
|
278
|
-
{
|
|
279
|
-
worker.initiate_shutdown();
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
self.workers.set_worker_for_task_queue(tq, worker)?;
|
|
284
|
-
Ok(())
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/// Allow construction of workers with mocked poll responses during testing
|
|
288
|
-
#[cfg(test)]
|
|
289
|
-
pub(crate) fn reg_worker_sync(&self, worker: MockWorker) {
|
|
290
|
-
let sticky_q = self.get_sticky_q_name_for_worker(&worker.config);
|
|
291
|
-
let tq = worker.config.task_queue.clone();
|
|
292
|
-
let worker = Worker::new_with_pollers(
|
|
293
|
-
worker.config,
|
|
294
|
-
sticky_q,
|
|
295
|
-
self.server_gateway.clone(),
|
|
296
|
-
worker.wf_poller,
|
|
297
|
-
worker.act_poller,
|
|
298
|
-
self.metrics.clone(),
|
|
299
|
-
);
|
|
300
|
-
self.workers.set_worker_for_task_queue(tq, worker).unwrap();
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
#[cfg(test)]
|
|
304
|
-
pub(crate) fn outstanding_wfts(&self, tq: &str) -> usize {
|
|
305
|
-
self.worker(tq).unwrap().outstanding_workflow_tasks()
|
|
306
|
-
}
|
|
307
|
-
#[cfg(test)]
|
|
308
|
-
pub(crate) fn available_wft_permits(&self, tq: &str) -> usize {
|
|
309
|
-
self.worker(tq).unwrap().available_wft_permits()
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
fn get_sticky_q_name_for_worker(&self, config: &WorkerConfig) -> Option<String> {
|
|
313
|
-
if config.max_cached_workflows > 0 {
|
|
314
|
-
Some(format!(
|
|
315
|
-
"{}-{}-{}",
|
|
316
|
-
&self.init_options.gateway_opts.identity, &config.task_queue, *PROCCESS_UNIQ_ID
|
|
317
|
-
))
|
|
318
|
-
} else {
|
|
319
|
-
None
|
|
65
|
+
/// Initialize a worker bound to a task queue
|
|
66
|
+
pub fn init_worker<CT>(worker_config: WorkerConfig, client: CT) -> Worker
|
|
67
|
+
where
|
|
68
|
+
CT: Into<AnyClient>,
|
|
69
|
+
{
|
|
70
|
+
let as_enum = client.into();
|
|
71
|
+
// TODO: Assert namespaces match
|
|
72
|
+
let client = match as_enum {
|
|
73
|
+
AnyClient::HighLevel(ac) => ac,
|
|
74
|
+
AnyClient::LowLevel(ll) => {
|
|
75
|
+
let client = Client::new(*ll, worker_config.namespace.clone());
|
|
76
|
+
let retry_client = RetryClient::new(client, RetryConfig::default());
|
|
77
|
+
Arc::new(retry_client)
|
|
320
78
|
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
Shutdown(String),
|
|
335
|
-
NoWorker(String),
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
impl From<WorkerLookupErr> for PollWfError {
|
|
339
|
-
fn from(e: WorkerLookupErr) -> Self {
|
|
340
|
-
match e {
|
|
341
|
-
WorkerLookupErr::Shutdown(_) => Self::ShutDown,
|
|
342
|
-
WorkerLookupErr::NoWorker(s) => Self::NoWorkerForQueue(s),
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
impl From<WorkerLookupErr> for PollActivityError {
|
|
348
|
-
fn from(e: WorkerLookupErr) -> Self {
|
|
349
|
-
match e {
|
|
350
|
-
WorkerLookupErr::Shutdown(_) => Self::ShutDown,
|
|
351
|
-
WorkerLookupErr::NoWorker(s) => Self::NoWorkerForQueue(s),
|
|
352
|
-
}
|
|
353
|
-
}
|
|
79
|
+
};
|
|
80
|
+
let c_opts = client.get_options().clone();
|
|
81
|
+
if client.namespace() != worker_config.namespace {
|
|
82
|
+
panic!("Passed in client is not bound to the same namespace as the worker");
|
|
83
|
+
}
|
|
84
|
+
let client_bag = Arc::new(WorkerClientBag::new(
|
|
85
|
+
Box::new(client),
|
|
86
|
+
worker_config.namespace.clone(),
|
|
87
|
+
));
|
|
88
|
+
let sticky_q = sticky_q_name_for_worker(&c_opts.identity, &worker_config);
|
|
89
|
+
let metrics = MetricsContext::top_level(worker_config.namespace.clone())
|
|
90
|
+
.with_task_q(worker_config.task_queue.clone());
|
|
91
|
+
Worker::new(worker_config, sticky_q, client_bag, metrics)
|
|
354
92
|
}
|
|
355
93
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
94
|
+
/// Create a worker for replaying a specific history. It will auto-shutdown as soon as the history
|
|
95
|
+
/// has finished being replayed. The provided client should be a mock, and this should only be used
|
|
96
|
+
/// for workflow testing purposes.
|
|
97
|
+
pub fn init_replay_worker(
|
|
98
|
+
mut config: WorkerConfig,
|
|
99
|
+
history: &History,
|
|
100
|
+
) -> Result<Worker, anyhow::Error> {
|
|
101
|
+
info!(
|
|
102
|
+
task_queue = config.task_queue.as_str(),
|
|
103
|
+
"Registering replay worker"
|
|
104
|
+
);
|
|
105
|
+
config.max_cached_workflows = 1;
|
|
106
|
+
config.max_concurrent_wft_polls = 1;
|
|
107
|
+
config.no_remote_activities = true;
|
|
108
|
+
// Could possibly just use mocked pollers here?
|
|
109
|
+
let client = mock_client_from_history(history, &config.task_queue);
|
|
110
|
+
let run_id = history.extract_run_id_from_start()?.to_string();
|
|
111
|
+
let last_event = history.last_event_id();
|
|
112
|
+
let mut worker = Worker::new(config, None, Arc::new(client), MetricsContext::default());
|
|
113
|
+
worker.set_shutdown_on_run_reaches_event(run_id, last_event);
|
|
114
|
+
Ok(worker)
|
|
364
115
|
}
|
|
365
116
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
117
|
+
pub(crate) fn sticky_q_name_for_worker(
|
|
118
|
+
process_identity: &str,
|
|
119
|
+
config: &WorkerConfig,
|
|
120
|
+
) -> Option<String> {
|
|
121
|
+
if config.max_cached_workflows > 0 {
|
|
122
|
+
Some(format!(
|
|
123
|
+
"{}-{}-{}",
|
|
124
|
+
&process_identity, &config.task_queue, *PROCCESS_UNIQ_ID
|
|
125
|
+
))
|
|
126
|
+
} else {
|
|
127
|
+
None
|
|
373
128
|
}
|
|
374
129
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
mod poll_buffer;
|
|
2
2
|
|
|
3
|
-
pub use poll_buffer::{
|
|
4
|
-
new_activity_task_buffer, new_workflow_task_buffer,
|
|
5
|
-
PollWorkflowTaskBuffer, WorkflowTaskPoller,
|
|
3
|
+
pub(crate) use poll_buffer::{
|
|
4
|
+
new_activity_task_buffer, new_workflow_task_buffer, WorkflowTaskPoller,
|
|
6
5
|
};
|
|
7
6
|
pub use temporal_client::{
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
Client, ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryClient, RetryConfig,
|
|
8
|
+
TlsConfig, WorkflowClientTrait,
|
|
10
9
|
};
|
|
11
|
-
|
|
12
10
|
use temporal_sdk_core_protos::temporal::api::workflowservice::v1::{
|
|
13
11
|
PollActivityTaskQueueResponse, PollWorkflowTaskQueueResponse,
|
|
14
12
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
pollers::{self, Poller},
|
|
3
|
-
|
|
3
|
+
worker::client::WorkerClientBag,
|
|
4
4
|
};
|
|
5
5
|
use futures::{prelude::stream::FuturesUnordered, StreamExt};
|
|
6
6
|
use std::{
|
|
@@ -197,8 +197,8 @@ impl Poller<PollWorkflowTaskQueueResponse> for WorkflowTaskPoller {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
pub type PollWorkflowTaskBuffer = LongPollBuffer<PollWorkflowTaskQueueResponse>;
|
|
200
|
-
pub fn new_workflow_task_buffer(
|
|
201
|
-
|
|
200
|
+
pub(crate) fn new_workflow_task_buffer(
|
|
201
|
+
client: Arc<WorkerClientBag>,
|
|
202
202
|
task_queue: String,
|
|
203
203
|
is_sticky: bool,
|
|
204
204
|
concurrent_pollers: usize,
|
|
@@ -206,9 +206,9 @@ pub fn new_workflow_task_buffer(
|
|
|
206
206
|
) -> PollWorkflowTaskBuffer {
|
|
207
207
|
LongPollBuffer::new(
|
|
208
208
|
move || {
|
|
209
|
-
let
|
|
209
|
+
let client = client.clone();
|
|
210
210
|
let task_queue = task_queue.clone();
|
|
211
|
-
async move {
|
|
211
|
+
async move { client.poll_workflow_task(task_queue, is_sticky).await }
|
|
212
212
|
},
|
|
213
213
|
concurrent_pollers,
|
|
214
214
|
buffer_size,
|
|
@@ -216,17 +216,18 @@ pub fn new_workflow_task_buffer(
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
pub type PollActivityTaskBuffer = LongPollBuffer<PollActivityTaskQueueResponse>;
|
|
219
|
-
pub fn new_activity_task_buffer(
|
|
220
|
-
|
|
219
|
+
pub(crate) fn new_activity_task_buffer(
|
|
220
|
+
client: Arc<WorkerClientBag>,
|
|
221
221
|
task_queue: String,
|
|
222
222
|
concurrent_pollers: usize,
|
|
223
223
|
buffer_size: usize,
|
|
224
|
+
max_tps: Option<f64>,
|
|
224
225
|
) -> PollActivityTaskBuffer {
|
|
225
226
|
LongPollBuffer::new(
|
|
226
227
|
move || {
|
|
227
|
-
let
|
|
228
|
+
let client = client.clone();
|
|
228
229
|
let task_queue = task_queue.clone();
|
|
229
|
-
async move {
|
|
230
|
+
async move { client.poll_activity_task(task_queue, max_tps).await }
|
|
230
231
|
},
|
|
231
232
|
concurrent_pollers,
|
|
232
233
|
buffer_size,
|
|
@@ -236,15 +237,15 @@ pub fn new_activity_task_buffer(
|
|
|
236
237
|
#[cfg(test)]
|
|
237
238
|
mod tests {
|
|
238
239
|
use super::*;
|
|
240
|
+
use crate::worker::client::mocks::mock_manual_workflow_client;
|
|
239
241
|
use futures::FutureExt;
|
|
240
242
|
use std::time::Duration;
|
|
241
|
-
use temporal_client::MockManualGateway;
|
|
242
243
|
use tokio::{select, sync::mpsc::channel};
|
|
243
244
|
|
|
244
245
|
#[tokio::test]
|
|
245
246
|
async fn only_polls_once_with_1_poller() {
|
|
246
|
-
let mut
|
|
247
|
-
|
|
247
|
+
let mut mock_client = mock_manual_workflow_client();
|
|
248
|
+
mock_client
|
|
248
249
|
.expect_poll_workflow_task()
|
|
249
250
|
.times(2)
|
|
250
251
|
.returning(move |_, _| {
|
|
@@ -254,9 +255,14 @@ mod tests {
|
|
|
254
255
|
}
|
|
255
256
|
.boxed()
|
|
256
257
|
});
|
|
257
|
-
let mock_gateway = Arc::new(mock_gateway);
|
|
258
258
|
|
|
259
|
-
let pb = new_workflow_task_buffer(
|
|
259
|
+
let pb = new_workflow_task_buffer(
|
|
260
|
+
Arc::new(mock_client.into()),
|
|
261
|
+
"someq".to_string(),
|
|
262
|
+
false,
|
|
263
|
+
1,
|
|
264
|
+
1,
|
|
265
|
+
);
|
|
260
266
|
|
|
261
267
|
// Poll a bunch of times, "interrupting" it each time, we should only actually have polled
|
|
262
268
|
// once since the poll takes a while
|
|
@@ -19,12 +19,13 @@ use temporal_sdk_core_protos::{
|
|
|
19
19
|
},
|
|
20
20
|
external_data::LocalActivityMarkerData,
|
|
21
21
|
workflow_activation::{
|
|
22
|
-
workflow_activation_job, QueryWorkflow, WorkflowActivation,
|
|
22
|
+
query_to_job, workflow_activation_job, QueryWorkflow, WorkflowActivation,
|
|
23
|
+
WorkflowActivationJob,
|
|
23
24
|
},
|
|
24
25
|
workflow_commands::{
|
|
25
26
|
query_result, ActivityCancellationType, QueryResult, ScheduleLocalActivity,
|
|
26
27
|
},
|
|
27
|
-
workflow_completion,
|
|
28
|
+
workflow_completion,
|
|
28
29
|
},
|
|
29
30
|
temporal::api::{
|
|
30
31
|
common::v1::{Payload, WorkflowExecution},
|
|
@@ -82,11 +83,7 @@ impl TryFrom<PollWorkflowTaskQueueResponse> for ValidPollWFTQResponse {
|
|
|
82
83
|
} => {
|
|
83
84
|
let query_requests = queries
|
|
84
85
|
.into_iter()
|
|
85
|
-
.map(|(id, q)|
|
|
86
|
-
query_id: id,
|
|
87
|
-
query_type: q.query_type,
|
|
88
|
-
arguments: Vec::from_payloads(q.query_args),
|
|
89
|
-
})
|
|
86
|
+
.map(|(id, q)| query_to_job(id, q))
|
|
90
87
|
.collect();
|
|
91
88
|
|
|
92
89
|
Ok(Self {
|
|
@@ -267,7 +264,7 @@ pub struct ValidScheduleLA {
|
|
|
267
264
|
pub activity_type: String,
|
|
268
265
|
pub attempt: u32,
|
|
269
266
|
pub original_schedule_time: Option<SystemTime>,
|
|
270
|
-
pub
|
|
267
|
+
pub headers: HashMap<String, SDKPayload>,
|
|
271
268
|
pub arguments: Vec<SDKPayload>,
|
|
272
269
|
pub schedule_to_start_timeout: Option<Duration>,
|
|
273
270
|
pub close_timeouts: LACloseTimeouts,
|
|
@@ -364,7 +361,7 @@ impl ValidScheduleLA {
|
|
|
364
361
|
};
|
|
365
362
|
let retry_policy = v
|
|
366
363
|
.retry_policy
|
|
367
|
-
.
|
|
364
|
+
.ok_or_else(|| anyhow!("Retry policy must be defined!"))?;
|
|
368
365
|
let local_retry_threshold = v
|
|
369
366
|
.local_retry_threshold
|
|
370
367
|
.clone()
|
|
@@ -378,7 +375,7 @@ impl ValidScheduleLA {
|
|
|
378
375
|
activity_type: v.activity_type,
|
|
379
376
|
attempt: v.attempt,
|
|
380
377
|
original_schedule_time,
|
|
381
|
-
|
|
378
|
+
headers: v.headers,
|
|
382
379
|
arguments: v.arguments,
|
|
383
380
|
schedule_to_start_timeout,
|
|
384
381
|
close_timeouts,
|