@temporalio/core-bridge 1.4.4 → 1.5.1
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 +327 -419
- package/Cargo.toml +1 -1
- package/index.js +25 -2
- package/lib/errors.d.ts +22 -0
- package/lib/errors.js +65 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +440 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/package.json +11 -5
- 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 +2 -2
- package/sdk-core/bridge-ffi/Cargo.toml +1 -1
- package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +0 -25
- package/sdk-core/bridge-ffi/src/lib.rs +29 -108
- package/sdk-core/bridge-ffi/src/wrappers.rs +35 -25
- package/sdk-core/client/Cargo.toml +1 -1
- package/sdk-core/client/src/lib.rs +12 -20
- package/sdk-core/client/src/raw.rs +9 -8
- package/sdk-core/client/src/retry.rs +100 -23
- package/sdk-core/core/Cargo.toml +5 -5
- package/sdk-core/core/benches/workflow_replay.rs +13 -10
- package/sdk-core/core/src/abstractions.rs +22 -22
- package/sdk-core/core/src/core_tests/activity_tasks.rs +1 -1
- package/sdk-core/core/src/core_tests/local_activities.rs +228 -6
- package/sdk-core/core/src/core_tests/queries.rs +247 -89
- package/sdk-core/core/src/core_tests/workers.rs +2 -2
- package/sdk-core/core/src/core_tests/workflow_cancels.rs +1 -1
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +46 -27
- package/sdk-core/core/src/lib.rs +139 -32
- package/sdk-core/core/src/replay/mod.rs +185 -41
- package/sdk-core/core/src/telemetry/log_export.rs +190 -0
- package/sdk-core/core/src/telemetry/metrics.rs +184 -139
- package/sdk-core/core/src/telemetry/mod.rs +296 -318
- package/sdk-core/core/src/telemetry/prometheus_server.rs +4 -3
- package/sdk-core/core/src/test_help/mod.rs +9 -7
- package/sdk-core/core/src/worker/activities/local_activities.rs +2 -1
- package/sdk-core/core/src/worker/activities.rs +40 -23
- package/sdk-core/core/src/worker/client/mocks.rs +1 -1
- package/sdk-core/core/src/worker/client.rs +30 -4
- package/sdk-core/core/src/worker/mod.rs +22 -18
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +10 -19
- package/sdk-core/core/src/worker/workflow/history_update.rs +99 -25
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +2 -6
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +18 -21
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -38
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +178 -0
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +8 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +232 -216
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -6
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +4 -4
- package/sdk-core/core/src/worker/workflow/managed_run.rs +13 -5
- package/sdk-core/core/src/worker/workflow/mod.rs +61 -9
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +2 -2
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +56 -11
- package/sdk-core/core-api/Cargo.toml +4 -3
- package/sdk-core/core-api/src/lib.rs +1 -43
- package/sdk-core/core-api/src/telemetry.rs +147 -0
- package/sdk-core/core-api/src/worker.rs +13 -0
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
- package/sdk-core/histories/evict_while_la_running_no_interference-23_history.bin +0 -0
- package/sdk-core/histories/evict_while_la_running_no_interference-85_history.bin +0 -0
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
- package/sdk-core/protos/api_upstream/buf.yaml +0 -3
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +3 -7
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +8 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -2
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +2 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +3 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +13 -0
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +19 -59
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +0 -19
- package/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +108 -29
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -2
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +47 -8
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +15 -1
- package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +8 -1
- package/sdk-core/sdk/src/interceptors.rs +36 -3
- package/sdk-core/sdk/src/lib.rs +7 -4
- package/sdk-core/sdk/src/workflow_context.rs +13 -2
- package/sdk-core/sdk-core-protos/src/history_builder.rs +47 -1
- package/sdk-core/sdk-core-protos/src/history_info.rs +22 -22
- package/sdk-core/sdk-core-protos/src/lib.rs +49 -27
- package/sdk-core/test-utils/Cargo.toml +1 -0
- package/sdk-core/test-utils/src/lib.rs +81 -29
- package/sdk-core/tests/integ_tests/metrics_tests.rs +37 -0
- package/sdk-core/tests/integ_tests/polling_tests.rs +0 -13
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +145 -4
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +53 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +106 -20
- package/sdk-core/tests/integ_tests/workflow_tests.rs +18 -8
- package/sdk-core/tests/main.rs +6 -4
- package/src/conversions.rs +52 -47
- package/src/errors.rs +28 -86
- package/src/helpers.rs +3 -4
- package/src/lib.rs +2 -2
- package/src/runtime.rs +132 -61
- package/src/testing.rs +7 -4
- package/src/worker.rs +67 -50
- package/ts/errors.ts +55 -0
- package/{index.d.ts → ts/index.ts} +121 -15
- package/sdk-core/core/src/log_export.rs +0 -62
- package/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +0 -127
- package/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +0 -71
- package/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +0 -83
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +0 -40
package/src/runtime.rs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
use crate::conversions
|
|
2
|
-
use
|
|
3
|
-
use crate::helpers::*;
|
|
4
|
-
use crate::worker::*;
|
|
1
|
+
use crate::{conversions::*, errors::*, helpers::*, worker::*};
|
|
2
|
+
use neon::context::Context;
|
|
5
3
|
use neon::prelude::*;
|
|
6
4
|
use parking_lot::RwLock;
|
|
5
|
+
use std::cell::Cell;
|
|
7
6
|
use std::{
|
|
8
7
|
cell::RefCell,
|
|
9
8
|
collections::HashMap,
|
|
@@ -12,17 +11,17 @@ use std::{
|
|
|
12
11
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
13
12
|
};
|
|
14
13
|
use temporal_client::{ClientInitError, ConfiguredClient, TemporalServiceClientWithMetrics};
|
|
15
|
-
use temporal_sdk_core::
|
|
14
|
+
use temporal_sdk_core::api::telemetry::{CoreTelemetry, TelemetryOptions};
|
|
15
|
+
use temporal_sdk_core::CoreRuntime;
|
|
16
16
|
use temporal_sdk_core::{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
WorkerConfig,
|
|
17
|
+
ephemeral_server::EphemeralServer as CoreEphemeralServer, init_replay_worker, init_worker,
|
|
18
|
+
replay::HistoryForReplay, ClientOptions, RetryClient, WorkerConfig,
|
|
20
19
|
};
|
|
21
|
-
use tokio::{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
sync::Mutex,
|
|
20
|
+
use tokio::sync::{
|
|
21
|
+
mpsc::{channel, unbounded_channel, Sender, UnboundedReceiver, UnboundedSender},
|
|
22
|
+
Mutex,
|
|
25
23
|
};
|
|
24
|
+
use tokio_stream::wrappers::ReceiverStream;
|
|
26
25
|
|
|
27
26
|
pub type RawClient = RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>;
|
|
28
27
|
|
|
@@ -84,10 +83,9 @@ pub enum RuntimeRequest {
|
|
|
84
83
|
},
|
|
85
84
|
/// A request to register a replay worker
|
|
86
85
|
InitReplayWorker {
|
|
86
|
+
runtime: Arc<RuntimeHandle>,
|
|
87
87
|
/// Worker configuration. Must have unique task queue name.
|
|
88
88
|
config: WorkerConfig,
|
|
89
|
-
/// The history this worker should replay
|
|
90
|
-
history: History,
|
|
91
89
|
/// Used to send the result back into JS
|
|
92
90
|
callback: Root<JsFunction>,
|
|
93
91
|
},
|
|
@@ -105,22 +103,27 @@ pub enum RuntimeRequest {
|
|
|
105
103
|
server: Arc<Mutex<CoreEphemeralServer>>,
|
|
106
104
|
callback: Root<JsFunction>,
|
|
107
105
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.enable_all()
|
|
114
|
-
.thread_name("core")
|
|
115
|
-
.build()
|
|
116
|
-
.expect("Tokio runtime must construct properly")
|
|
106
|
+
PushReplayHistory {
|
|
107
|
+
tx: Sender<HistoryForReplay>,
|
|
108
|
+
pushme: HistoryForReplay,
|
|
109
|
+
callback: Root<JsFunction>,
|
|
110
|
+
},
|
|
117
111
|
}
|
|
118
112
|
|
|
119
113
|
/// Builds a tokio runtime and starts polling on [RuntimeRequest]s via an internal channel.
|
|
120
114
|
/// Bridges requests from JS to core and sends responses back to JS using a neon::Channel.
|
|
121
115
|
/// Blocks current thread until a [Shutdown] request is received in channel.
|
|
122
|
-
pub fn start_bridge_loop(
|
|
123
|
-
|
|
116
|
+
pub fn start_bridge_loop(
|
|
117
|
+
telemetry_options: TelemetryOptions,
|
|
118
|
+
channel: Arc<Channel>,
|
|
119
|
+
receiver: &mut UnboundedReceiver<RuntimeRequest>,
|
|
120
|
+
) {
|
|
121
|
+
let mut tokio_builder = tokio::runtime::Builder::new_multi_thread();
|
|
122
|
+
tokio_builder.enable_all().thread_name("core");
|
|
123
|
+
let core_runtime =
|
|
124
|
+
CoreRuntime::new(telemetry_options, tokio_builder).expect("Failed to create CoreRuntime");
|
|
125
|
+
|
|
126
|
+
core_runtime.tokio_handle().block_on(async {
|
|
124
127
|
loop {
|
|
125
128
|
let request_option = receiver.recv().await;
|
|
126
129
|
let request = match request_option {
|
|
@@ -145,23 +148,25 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
145
148
|
// returned client directly at the moment, when we repurpose the client to be
|
|
146
149
|
// used by a Worker, `init_worker` will attach the correct metrics meter for
|
|
147
150
|
// us.
|
|
148
|
-
|
|
151
|
+
core_runtime.tokio_handle().spawn(async move {
|
|
149
152
|
match options
|
|
150
153
|
.connect_no_namespace(None, headers.map(|h| Arc::new(RwLock::new(h))))
|
|
151
154
|
.await
|
|
152
155
|
{
|
|
153
156
|
Err(err) => {
|
|
154
157
|
send_error(channel.clone(), callback, |cx| match err {
|
|
155
|
-
ClientInitError::SystemInfoCallError(e) =>
|
|
156
|
-
|
|
158
|
+
ClientInitError::SystemInfoCallError(e) => {
|
|
159
|
+
make_named_error_from_string(
|
|
157
160
|
cx,
|
|
161
|
+
TRANSPORT_ERROR,
|
|
158
162
|
format!("Failed to call GetSystemInfo: {}", e),
|
|
159
|
-
)
|
|
163
|
+
)
|
|
164
|
+
}
|
|
160
165
|
ClientInitError::TonicTransportError(e) => {
|
|
161
|
-
|
|
166
|
+
make_named_error_from_error(cx, TRANSPORT_ERROR, e)
|
|
162
167
|
}
|
|
163
168
|
ClientInitError::InvalidUri(e) => {
|
|
164
|
-
Ok(JsError::type_error(cx, format!("{}", e))
|
|
169
|
+
Ok(JsError::type_error(cx, format!("{}", e))?)
|
|
165
170
|
}
|
|
166
171
|
});
|
|
167
172
|
}
|
|
@@ -185,7 +190,7 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
185
190
|
send_result(channel.clone(), callback, |cx| Ok(cx.undefined()));
|
|
186
191
|
}
|
|
187
192
|
RuntimeRequest::PollLogs { callback } => {
|
|
188
|
-
let logs =
|
|
193
|
+
let logs = core_runtime.telemetry().fetch_buffered_logs();
|
|
189
194
|
send_result(channel.clone(), callback, |cx| {
|
|
190
195
|
let logarr = cx.empty_array();
|
|
191
196
|
for (i, cl) in logs.into_iter().enumerate() {
|
|
@@ -209,28 +214,49 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
209
214
|
callback,
|
|
210
215
|
} => {
|
|
211
216
|
let client = (*client).clone();
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
match init_worker(&core_runtime, config, client.into_inner()) {
|
|
218
|
+
Ok(worker) => {
|
|
219
|
+
let (tx, rx) = unbounded_channel();
|
|
220
|
+
core_runtime.tokio_handle().spawn(start_worker_loop(
|
|
221
|
+
worker,
|
|
222
|
+
rx,
|
|
223
|
+
channel.clone(),
|
|
224
|
+
));
|
|
225
|
+
send_result(channel.clone(), callback, |cx| {
|
|
226
|
+
Ok(cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx }))))
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
Err(err) => send_error(channel.clone(), callback, move |cx| {
|
|
230
|
+
make_named_error_from_error(cx, UNEXPECTED_ERROR, err.deref())
|
|
231
|
+
}),
|
|
232
|
+
}
|
|
218
233
|
}
|
|
219
234
|
RuntimeRequest::InitReplayWorker {
|
|
235
|
+
runtime,
|
|
220
236
|
config,
|
|
221
|
-
history,
|
|
222
237
|
callback,
|
|
223
238
|
} => {
|
|
224
|
-
|
|
239
|
+
let (tunnel, stream) = HistoryForReplayTunnel::new(runtime);
|
|
240
|
+
match init_replay_worker(config, Box::pin(stream)) {
|
|
225
241
|
Ok(worker) => {
|
|
226
242
|
let (tx, rx) = unbounded_channel();
|
|
227
|
-
|
|
243
|
+
core_runtime.tokio_handle().spawn(start_worker_loop(
|
|
244
|
+
worker,
|
|
245
|
+
rx,
|
|
246
|
+
channel.clone(),
|
|
247
|
+
));
|
|
228
248
|
send_result(channel.clone(), callback, |cx| {
|
|
229
|
-
|
|
249
|
+
let worker =
|
|
250
|
+
cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx })));
|
|
251
|
+
let tunnel = cx.boxed(tunnel);
|
|
252
|
+
let retme = cx.empty_object();
|
|
253
|
+
retme.set(cx, "worker", worker)?;
|
|
254
|
+
retme.set(cx, "pusher", tunnel)?;
|
|
255
|
+
Ok(retme)
|
|
230
256
|
})
|
|
231
257
|
}
|
|
232
258
|
Err(err) => send_error(channel.clone(), callback, move |cx| {
|
|
233
|
-
|
|
259
|
+
make_named_error_from_error(cx, UNEXPECTED_ERROR, err.deref())
|
|
234
260
|
}),
|
|
235
261
|
};
|
|
236
262
|
}
|
|
@@ -239,7 +265,7 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
239
265
|
config,
|
|
240
266
|
callback,
|
|
241
267
|
} => {
|
|
242
|
-
|
|
268
|
+
core_runtime.tokio_handle().spawn(async move {
|
|
243
269
|
let result = match config {
|
|
244
270
|
EphemeralServerConfig::TestServer(config) => {
|
|
245
271
|
config.start_server().await
|
|
@@ -252,7 +278,7 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
252
278
|
Err(err) => {
|
|
253
279
|
let err_str = format!("Failed to start ephemeral server: {}", err);
|
|
254
280
|
send_error(channel.clone(), callback, |cx| {
|
|
255
|
-
|
|
281
|
+
make_named_error_from_string(cx, UNEXPECTED_ERROR, err_str)
|
|
256
282
|
});
|
|
257
283
|
}
|
|
258
284
|
Ok(server) => {
|
|
@@ -267,7 +293,7 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
267
293
|
});
|
|
268
294
|
}
|
|
269
295
|
RuntimeRequest::ShutdownEphemeralServer { server, callback } => {
|
|
270
|
-
|
|
296
|
+
core_runtime.tokio_handle().spawn(async move {
|
|
271
297
|
void_future_to_js(
|
|
272
298
|
channel,
|
|
273
299
|
callback,
|
|
@@ -276,8 +302,9 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
276
302
|
guard.shutdown().await
|
|
277
303
|
},
|
|
278
304
|
|cx, err| {
|
|
279
|
-
|
|
305
|
+
make_named_error_from_string(
|
|
280
306
|
cx,
|
|
307
|
+
UNEXPECTED_ERROR,
|
|
281
308
|
format!("Failed to start test server: {}", err),
|
|
282
309
|
)
|
|
283
310
|
},
|
|
@@ -285,6 +312,30 @@ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver
|
|
|
285
312
|
.await
|
|
286
313
|
});
|
|
287
314
|
}
|
|
315
|
+
RuntimeRequest::PushReplayHistory {
|
|
316
|
+
tx,
|
|
317
|
+
pushme,
|
|
318
|
+
callback,
|
|
319
|
+
} => {
|
|
320
|
+
core_runtime.tokio_handle().spawn(async move {
|
|
321
|
+
let sendfut = async move {
|
|
322
|
+
tx.send(pushme).await.map_err(|e| {
|
|
323
|
+
format!(
|
|
324
|
+
"Receive side of history replay channel is gone. This is an sdk bug. {:?}",
|
|
325
|
+
e
|
|
326
|
+
)
|
|
327
|
+
})
|
|
328
|
+
};
|
|
329
|
+
void_future_to_js(channel, callback, sendfut, |cx, err| {
|
|
330
|
+
make_named_error_from_string(
|
|
331
|
+
cx,
|
|
332
|
+
UNEXPECTED_ERROR,
|
|
333
|
+
format!("Error pushing replay history {}", err),
|
|
334
|
+
)
|
|
335
|
+
})
|
|
336
|
+
.await
|
|
337
|
+
});
|
|
338
|
+
}
|
|
288
339
|
}
|
|
289
340
|
}
|
|
290
341
|
})
|
|
@@ -314,24 +365,15 @@ pub fn get_time_of_day(mut cx: FunctionContext) -> JsResult<JsArray> {
|
|
|
314
365
|
system_time_to_js(&mut cx, SystemTime::now())
|
|
315
366
|
}
|
|
316
367
|
|
|
317
|
-
/// Initialize Core global telemetry.
|
|
368
|
+
/// Initialize Core global telemetry and create the tokio runtime required to run Core.
|
|
318
369
|
/// This should typically be called once on process startup.
|
|
319
|
-
pub fn init_telemetry(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
320
|
-
let telemetry_options = cx.argument::<JsObject>(0)?.as_telemetry_options(&mut cx)?;
|
|
321
|
-
telemetry_init(&telemetry_options).map_err(|err| {
|
|
322
|
-
cx.throw_type_error::<String, ()>(format!("{}", err))
|
|
323
|
-
.unwrap_err()
|
|
324
|
-
})?;
|
|
325
|
-
Ok(cx.undefined())
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/// Create the tokio runtime required to run Core.
|
|
329
370
|
/// Immediately spawns a poller thread that will block on [RuntimeRequest]s
|
|
330
371
|
pub fn runtime_new(mut cx: FunctionContext) -> JsResult<BoxedRuntime> {
|
|
372
|
+
let telemetry_options = cx.argument::<JsObject>(0)?.as_telemetry_options(&mut cx)?;
|
|
331
373
|
let channel = Arc::new(cx.channel());
|
|
332
374
|
let (sender, mut receiver) = unbounded_channel::<RuntimeRequest>();
|
|
333
375
|
|
|
334
|
-
std::thread::spawn(move || start_bridge_loop(channel, &mut receiver));
|
|
376
|
+
std::thread::spawn(move || start_bridge_loop(telemetry_options, channel, &mut receiver));
|
|
335
377
|
|
|
336
378
|
Ok(cx.boxed(Arc::new(RuntimeHandle { sender })))
|
|
337
379
|
}
|
|
@@ -401,8 +443,7 @@ pub fn client_new(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
|
401
443
|
pub fn client_close(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
402
444
|
let client = cx.argument::<BoxedClient>(0)?;
|
|
403
445
|
if client.replace(None).is_none() {
|
|
404
|
-
ILLEGAL_STATE_ERROR
|
|
405
|
-
.from_string(&mut cx, "Client already closed")
|
|
446
|
+
make_named_error_from_string(&mut cx, ILLEGAL_STATE_ERROR, "Client already closed")
|
|
406
447
|
.and_then(|err| cx.throw(err))?;
|
|
407
448
|
};
|
|
408
449
|
Ok(cx.undefined())
|
|
@@ -434,3 +475,33 @@ pub fn client_update_headers(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
|
434
475
|
|
|
435
476
|
Ok(cx.undefined())
|
|
436
477
|
}
|
|
478
|
+
|
|
479
|
+
pub(crate) struct HistoryForReplayTunnel {
|
|
480
|
+
pub(crate) runtime: Arc<RuntimeHandle>,
|
|
481
|
+
sender: Cell<Option<Sender<HistoryForReplay>>>,
|
|
482
|
+
}
|
|
483
|
+
impl HistoryForReplayTunnel {
|
|
484
|
+
fn new(runtime: Arc<RuntimeHandle>) -> (Self, ReceiverStream<HistoryForReplay>) {
|
|
485
|
+
let (sender, rx) = channel(1);
|
|
486
|
+
(
|
|
487
|
+
HistoryForReplayTunnel {
|
|
488
|
+
runtime,
|
|
489
|
+
sender: Cell::new(Some(sender)),
|
|
490
|
+
},
|
|
491
|
+
ReceiverStream::new(rx),
|
|
492
|
+
)
|
|
493
|
+
}
|
|
494
|
+
pub fn get_chan(&self) -> Result<Sender<HistoryForReplay>, &'static str> {
|
|
495
|
+
let chan = self.sender.take();
|
|
496
|
+
self.sender.set(chan.clone());
|
|
497
|
+
if let Some(chan) = chan {
|
|
498
|
+
Ok(chan)
|
|
499
|
+
} else {
|
|
500
|
+
Err("History replay channel is already closed")
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
pub fn shutdown(&self) {
|
|
504
|
+
self.sender.take();
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
impl Finalize for HistoryForReplayTunnel {}
|
package/src/testing.rs
CHANGED
|
@@ -32,11 +32,14 @@ pub fn get_ephemeral_server_target(mut cx: FunctionContext) -> JsResult<JsString
|
|
|
32
32
|
let target = server
|
|
33
33
|
.borrow()
|
|
34
34
|
.as_ref()
|
|
35
|
-
.map(|s| cx.string(s.core_server.blocking_lock().target.
|
|
35
|
+
.map(|s| cx.string(s.core_server.blocking_lock().target.as_str()));
|
|
36
36
|
if target.is_none() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
make_named_error_from_string(
|
|
38
|
+
&mut cx,
|
|
39
|
+
ILLEGAL_STATE_ERROR,
|
|
40
|
+
"Tried to use closed test server",
|
|
41
|
+
)
|
|
42
|
+
.and_then(|err| cx.throw(err))?;
|
|
40
43
|
};
|
|
41
44
|
Ok(target.unwrap())
|
|
42
45
|
}
|
package/src/worker.rs
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
use crate::conversions::ObjectHandleConversionsExt;
|
|
2
|
-
use crate::errors::*;
|
|
3
|
-
use crate::helpers::*;
|
|
4
|
-
use crate::runtime::*;
|
|
1
|
+
use crate::{conversions::ObjectHandleConversionsExt, errors::*, helpers::*, runtime::*};
|
|
5
2
|
use futures::stream::StreamExt;
|
|
6
|
-
use neon::prelude
|
|
7
|
-
use neon::types::buffer::TypedArray;
|
|
3
|
+
use neon::{prelude::*, types::buffer::TypedArray};
|
|
8
4
|
use opentelemetry::trace::{FutureExt, SpanContext, TraceContextExt};
|
|
9
5
|
use prost::Message;
|
|
10
6
|
use std::{cell::RefCell, sync::Arc};
|
|
7
|
+
use temporal_sdk_core::replay::HistoryForReplay;
|
|
11
8
|
use temporal_sdk_core::{
|
|
12
9
|
api::{
|
|
13
10
|
errors::{CompleteActivityError, CompleteWfError, PollActivityError, PollWfError},
|
|
@@ -96,7 +93,7 @@ pub async fn start_worker_loop(
|
|
|
96
93
|
callback,
|
|
97
94
|
} => {
|
|
98
95
|
handle_poll_workflow_activation_request(
|
|
99
|
-
|
|
96
|
+
worker, otel_span, channel, callback,
|
|
100
97
|
)
|
|
101
98
|
.await
|
|
102
99
|
}
|
|
@@ -104,7 +101,7 @@ pub async fn start_worker_loop(
|
|
|
104
101
|
otel_span,
|
|
105
102
|
callback,
|
|
106
103
|
} => {
|
|
107
|
-
handle_poll_activity_task_request(
|
|
104
|
+
handle_poll_activity_task_request(worker, otel_span, channel, callback)
|
|
108
105
|
.await
|
|
109
106
|
}
|
|
110
107
|
WorkerRequest::CompleteWorkflowActivation {
|
|
@@ -196,12 +193,12 @@ async fn handle_poll_workflow_activation_request(
|
|
|
196
193
|
}
|
|
197
194
|
Err(err) => {
|
|
198
195
|
send_error(channel, callback, move |cx| match err {
|
|
199
|
-
PollWfError::ShutDown =>
|
|
200
|
-
PollWfError::TonicError(_) =>
|
|
196
|
+
PollWfError::ShutDown => make_named_error_from_error(cx, SHUTDOWN_ERROR, err),
|
|
197
|
+
PollWfError::TonicError(_) => make_named_error_from_error(cx, TRANSPORT_ERROR, err),
|
|
201
198
|
PollWfError::AutocompleteError(CompleteWfError::MalformedWorkflowCompletion {
|
|
202
199
|
reason,
|
|
203
200
|
..
|
|
204
|
-
}) => Ok(JsError::type_error(cx, reason)
|
|
201
|
+
}) => Ok(JsError::type_error(cx, reason)?),
|
|
205
202
|
});
|
|
206
203
|
}
|
|
207
204
|
}
|
|
@@ -229,8 +226,10 @@ pub async fn handle_poll_activity_task_request(
|
|
|
229
226
|
}
|
|
230
227
|
Err(err) => {
|
|
231
228
|
send_error(channel, callback, move |cx| match err {
|
|
232
|
-
PollActivityError::ShutDown =>
|
|
233
|
-
PollActivityError::TonicError(_) =>
|
|
229
|
+
PollActivityError::ShutDown => make_named_error_from_error(cx, SHUTDOWN_ERROR, err),
|
|
230
|
+
PollActivityError::TonicError(_) => {
|
|
231
|
+
make_named_error_from_error(cx, TRANSPORT_ERROR, err)
|
|
232
|
+
}
|
|
234
233
|
});
|
|
235
234
|
}
|
|
236
235
|
}
|
|
@@ -270,27 +269,51 @@ pub fn worker_new(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
|
270
269
|
pub fn replay_worker_new(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
271
270
|
let runtime = cx.argument::<BoxedRuntime>(0)?;
|
|
272
271
|
let worker_options = cx.argument::<JsObject>(1)?;
|
|
273
|
-
let
|
|
274
|
-
let callback = cx.argument::<JsFunction>(3)?;
|
|
272
|
+
let callback = cx.argument::<JsFunction>(2)?;
|
|
275
273
|
|
|
276
274
|
let config = worker_options.as_worker_config(&mut cx)?;
|
|
277
|
-
let
|
|
275
|
+
let request = RuntimeRequest::InitReplayWorker {
|
|
276
|
+
runtime: (*runtime).clone(),
|
|
277
|
+
config,
|
|
278
|
+
callback: callback.root(&mut cx),
|
|
279
|
+
};
|
|
280
|
+
if let Err(err) = runtime.sender.send(request) {
|
|
281
|
+
callback_with_unexpected_error(&mut cx, callback, err)?;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
Ok(cx.undefined())
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fn push_history(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
288
|
+
let pusher = cx.argument::<JsBox<HistoryForReplayTunnel>>(0)?;
|
|
289
|
+
let workflow_id = cx.argument::<JsString>(1)?;
|
|
290
|
+
let history_binary = cx.argument::<JsArrayBuffer>(2)?;
|
|
291
|
+
let callback = cx.argument::<JsFunction>(3)?;
|
|
292
|
+
let data = history_binary.as_slice(&cx);
|
|
278
293
|
match History::decode_length_delimited(data) {
|
|
279
|
-
Ok(
|
|
280
|
-
let
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
294
|
+
Ok(hist) => {
|
|
295
|
+
let workflow_id = workflow_id.value(&mut cx);
|
|
296
|
+
if let Err(e) = pusher.get_chan().map(|chan| {
|
|
297
|
+
pusher
|
|
298
|
+
.runtime
|
|
299
|
+
.sender
|
|
300
|
+
.send(RuntimeRequest::PushReplayHistory {
|
|
301
|
+
tx: chan,
|
|
302
|
+
pushme: HistoryForReplay::new(hist, workflow_id),
|
|
303
|
+
callback: callback.root(&mut cx),
|
|
304
|
+
})
|
|
305
|
+
}) {
|
|
306
|
+
callback_with_unexpected_error(&mut cx, callback, e)?;
|
|
307
|
+
}
|
|
308
|
+
Ok(cx.undefined())
|
|
288
309
|
}
|
|
289
|
-
Err(
|
|
290
|
-
JsError::type_error(cx, "Cannot decode History from buffer")
|
|
291
|
-
})?,
|
|
310
|
+
Err(e) => cx.throw_error(format!("Error decoding history: {:?}", e)),
|
|
292
311
|
}
|
|
312
|
+
}
|
|
293
313
|
|
|
314
|
+
pub fn close_history_stream(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
315
|
+
let pusher = cx.argument::<JsBox<HistoryForReplayTunnel>>(0)?;
|
|
316
|
+
pusher.shutdown();
|
|
294
317
|
Ok(cx.undefined())
|
|
295
318
|
}
|
|
296
319
|
|
|
@@ -351,9 +374,7 @@ pub fn worker_complete_workflow_activation(mut cx: FunctionContext) -> JsResult<
|
|
|
351
374
|
callback_with_unexpected_error(&mut cx, callback, "Tried to use closed Worker")?;
|
|
352
375
|
}
|
|
353
376
|
Some(worker) => {
|
|
354
|
-
match WorkflowActivationCompletion::decode_length_delimited(
|
|
355
|
-
completion.as_slice(&mut cx),
|
|
356
|
-
) {
|
|
377
|
+
match WorkflowActivationCompletion::decode_length_delimited(completion.as_slice(&cx)) {
|
|
357
378
|
Ok(completion) => {
|
|
358
379
|
let request = WorkerRequest::CompleteWorkflowActivation {
|
|
359
380
|
completion,
|
|
@@ -384,7 +405,7 @@ pub fn worker_complete_activity_task(mut cx: FunctionContext) -> JsResult<JsUnde
|
|
|
384
405
|
callback_with_unexpected_error(&mut cx, callback, "Tried to use closed Worker")?;
|
|
385
406
|
}
|
|
386
407
|
Some(worker) => {
|
|
387
|
-
match ActivityTaskCompletion::decode_length_delimited(result.as_slice(&
|
|
408
|
+
match ActivityTaskCompletion::decode_length_delimited(result.as_slice(&cx)) {
|
|
388
409
|
Ok(completion) => {
|
|
389
410
|
let request = WorkerRequest::CompleteActivityTask {
|
|
390
411
|
completion,
|
|
@@ -409,22 +430,20 @@ pub fn worker_record_activity_heartbeat(mut cx: FunctionContext) -> JsResult<JsU
|
|
|
409
430
|
let worker = cx.argument::<BoxedWorker>(0)?;
|
|
410
431
|
let heartbeat = cx.argument::<JsArrayBuffer>(1)?;
|
|
411
432
|
match worker.borrow().as_ref() {
|
|
412
|
-
None =>
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
.and_then(|err| cx.throw(err))?;
|
|
423
|
-
}
|
|
433
|
+
None => {
|
|
434
|
+
make_named_error_from_string(&mut cx, UNEXPECTED_ERROR, "Tried to use closed Worker")
|
|
435
|
+
.and_then(|err| cx.throw(err))?
|
|
436
|
+
}
|
|
437
|
+
Some(worker) => match ActivityHeartbeat::decode_length_delimited(heartbeat.as_slice(&cx)) {
|
|
438
|
+
Ok(heartbeat) => {
|
|
439
|
+
let request = WorkerRequest::RecordActivityHeartbeat { heartbeat };
|
|
440
|
+
if let Err(err) = worker.sender.send(request) {
|
|
441
|
+
make_named_error_from_error(&mut cx, UNEXPECTED_ERROR, err)
|
|
442
|
+
.and_then(|err| cx.throw(err))?;
|
|
424
443
|
}
|
|
425
|
-
Err(_) => cx.throw_type_error("Cannot decode ActivityHeartbeat from buffer")?,
|
|
426
444
|
}
|
|
427
|
-
|
|
445
|
+
Err(_) => cx.throw_type_error("Cannot decode ActivityHeartbeat from buffer")?,
|
|
446
|
+
},
|
|
428
447
|
};
|
|
429
448
|
Ok(cx.undefined())
|
|
430
449
|
}
|
|
@@ -444,8 +463,7 @@ pub fn worker_initiate_shutdown(mut cx: FunctionContext) -> JsResult<JsUndefined
|
|
|
444
463
|
if let Err(err) = worker.sender.send(WorkerRequest::InitiateShutdown {
|
|
445
464
|
callback: callback.root(&mut cx),
|
|
446
465
|
}) {
|
|
447
|
-
UNEXPECTED_ERROR
|
|
448
|
-
.from_error(&mut cx, err)
|
|
466
|
+
make_named_error_from_error(&mut cx, UNEXPECTED_ERROR, err)
|
|
449
467
|
.and_then(|err| cx.throw(err))?;
|
|
450
468
|
};
|
|
451
469
|
}
|
|
@@ -456,8 +474,7 @@ pub fn worker_initiate_shutdown(mut cx: FunctionContext) -> JsResult<JsUndefined
|
|
|
456
474
|
pub fn worker_finalize_shutdown(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
|
457
475
|
let worker = cx.argument::<BoxedWorker>(0)?;
|
|
458
476
|
if worker.replace(None).is_none() {
|
|
459
|
-
ILLEGAL_STATE_ERROR
|
|
460
|
-
.from_string(&mut cx, "Worker already closed")
|
|
477
|
+
make_named_error_from_string(&mut cx, ILLEGAL_STATE_ERROR, "Worker already closed")
|
|
461
478
|
.and_then(|err| cx.throw(err))?;
|
|
462
479
|
}
|
|
463
480
|
|
package/ts/errors.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { IllegalStateError } from '@temporalio/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The worker has been shut down
|
|
5
|
+
*/
|
|
6
|
+
export class ShutdownError extends Error {
|
|
7
|
+
public readonly name = 'ShutdownError';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Thrown after shutdown was requested as a response to a poll function, JS should stop polling
|
|
12
|
+
* once this error is encountered
|
|
13
|
+
*/
|
|
14
|
+
export class TransportError extends Error {
|
|
15
|
+
public readonly name = 'TransportError';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Something unexpected happened, considered fatal
|
|
20
|
+
*/
|
|
21
|
+
export class UnexpectedError extends Error {
|
|
22
|
+
public readonly name = 'UnexpectedError';
|
|
23
|
+
}
|
|
24
|
+
export { IllegalStateError };
|
|
25
|
+
|
|
26
|
+
export function convertFromNamedError(e: unknown, keepStackTrace: boolean): unknown {
|
|
27
|
+
// Check if the error's class is exactly Error (not a descendant of it).
|
|
28
|
+
// The instanceof check both ensure that e is indeed an object AND avoid
|
|
29
|
+
// TypeScript from complaining on accessing Error properties.
|
|
30
|
+
if (e instanceof Error && Object.getPrototypeOf(e).name === 'Error') {
|
|
31
|
+
let newerr: Error;
|
|
32
|
+
switch (e.name) {
|
|
33
|
+
case 'TransportError':
|
|
34
|
+
newerr = new TransportError(e.message);
|
|
35
|
+
newerr.stack = keepStackTrace ? e.stack : undefined;
|
|
36
|
+
return newerr;
|
|
37
|
+
|
|
38
|
+
case 'IllegalStateError':
|
|
39
|
+
newerr = new IllegalStateError(e.message);
|
|
40
|
+
newerr.stack = keepStackTrace ? e.stack : undefined;
|
|
41
|
+
return newerr;
|
|
42
|
+
|
|
43
|
+
case 'ShutdownError':
|
|
44
|
+
newerr = new ShutdownError(e.message);
|
|
45
|
+
newerr.stack = keepStackTrace ? e.stack : undefined;
|
|
46
|
+
return newerr;
|
|
47
|
+
|
|
48
|
+
case 'UnexpectedError':
|
|
49
|
+
newerr = new UnexpectedError(e.message);
|
|
50
|
+
newerr.stack = keepStackTrace ? e.stack : undefined;
|
|
51
|
+
return newerr;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return e;
|
|
55
|
+
}
|