@temporalio/core-bridge 1.1.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/Cargo.lock +765 -128
  2. package/Cargo.toml +2 -2
  3. package/common.js +7 -3
  4. package/index.d.ts +118 -5
  5. package/index.js +2 -6
  6. package/package.json +2 -3
  7. package/releases/aarch64-apple-darwin/index.node +0 -0
  8. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  9. package/releases/x86_64-apple-darwin/index.node +0 -0
  10. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  11. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  12. package/scripts/build.js +4 -3
  13. package/sdk-core/.buildkite/docker/Dockerfile +2 -1
  14. package/sdk-core/.buildkite/pipeline.yml +2 -0
  15. package/sdk-core/.cargo/config.toml +1 -1
  16. package/sdk-core/ARCHITECTURE.md +2 -2
  17. package/sdk-core/README.md +12 -0
  18. package/sdk-core/bridge-ffi/Cargo.toml +2 -2
  19. package/sdk-core/bridge-ffi/src/lib.rs +2 -2
  20. package/sdk-core/client/Cargo.toml +7 -5
  21. package/sdk-core/client/src/lib.rs +354 -226
  22. package/sdk-core/client/src/metrics.rs +13 -11
  23. package/sdk-core/client/src/raw.rs +352 -107
  24. package/sdk-core/client/src/retry.rs +188 -147
  25. package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
  26. package/sdk-core/core/Cargo.toml +28 -15
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +98 -33
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
  29. package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
  30. package/sdk-core/core/src/core_tests/workers.rs +3 -2
  31. package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
  32. package/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
  33. package/sdk-core/core/src/lib.rs +62 -28
  34. package/sdk-core/core/src/pollers/mod.rs +2 -0
  35. package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
  36. package/sdk-core/core/src/replay/mod.rs +3 -3
  37. package/sdk-core/core/src/retry_logic.rs +10 -9
  38. package/sdk-core/core/src/telemetry/metrics.rs +48 -39
  39. package/sdk-core/core/src/telemetry/mod.rs +46 -12
  40. package/sdk-core/core/src/telemetry/prometheus_server.rs +17 -13
  41. package/sdk-core/core/src/test_help/mod.rs +18 -8
  42. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
  43. package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
  44. package/sdk-core/core/src/worker/activities.rs +6 -12
  45. package/sdk-core/core/src/worker/client/mocks.rs +1 -0
  46. package/sdk-core/core/src/worker/client.rs +193 -64
  47. package/sdk-core/core/src/worker/mod.rs +14 -19
  48. package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
  49. package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
  50. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
  51. package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
  52. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
  53. package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
  54. package/sdk-core/core/src/worker/workflow/mod.rs +62 -58
  55. package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
  56. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
  57. package/sdk-core/core-api/Cargo.toml +3 -3
  58. package/sdk-core/core-api/src/errors.rs +3 -11
  59. package/sdk-core/core-api/src/worker.rs +7 -0
  60. package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
  61. package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
  62. package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
  63. package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
  64. package/sdk-core/protos/api_upstream/Makefile +2 -2
  65. package/sdk-core/protos/api_upstream/buf.yaml +1 -0
  66. package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
  67. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
  68. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
  69. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
  70. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
  73. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
  74. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
  75. package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
  80. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
  81. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
  82. package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
  84. package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
  85. package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
  86. package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
  87. package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
  88. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
  89. package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
  90. package/sdk-core/sdk/Cargo.toml +2 -2
  91. package/sdk-core/sdk/src/lib.rs +2 -2
  92. package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
  93. package/sdk-core/sdk/src/workflow_context.rs +30 -6
  94. package/sdk-core/sdk/src/workflow_future.rs +4 -4
  95. package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
  96. package/sdk-core/sdk-core-protos/build.rs +9 -1
  97. package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
  98. package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
  99. package/sdk-core/test-utils/Cargo.toml +3 -3
  100. package/sdk-core/test-utils/src/canned_histories.rs +58 -0
  101. package/sdk-core/test-utils/src/lib.rs +35 -12
  102. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
  103. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
  104. package/sdk-core/tests/integ_tests/polling_tests.rs +2 -1
  105. package/sdk-core/tests/integ_tests/queries_tests.rs +5 -5
  106. package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
  107. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
  108. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
  109. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
  110. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +2 -6
  111. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
  112. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
  113. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
  114. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +8 -2
  115. package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
  116. package/sdk-core/tests/load_tests.rs +2 -1
  117. package/sdk-core/tests/main.rs +17 -0
  118. package/sdk-core/tests/runner.rs +93 -0
  119. package/src/conversions.rs +157 -94
  120. package/src/helpers.rs +190 -0
  121. package/src/lib.rs +10 -912
  122. package/src/runtime.rs +436 -0
  123. package/src/testing.rs +67 -0
  124. package/src/worker.rs +465 -0
package/src/runtime.rs ADDED
@@ -0,0 +1,436 @@
1
+ use crate::conversions::*;
2
+ use crate::errors::*;
3
+ use crate::helpers::*;
4
+ use crate::worker::*;
5
+ use neon::prelude::*;
6
+ use parking_lot::RwLock;
7
+ use std::{
8
+ cell::RefCell,
9
+ collections::HashMap,
10
+ ops::Deref,
11
+ sync::Arc,
12
+ time::{Duration, SystemTime, UNIX_EPOCH},
13
+ };
14
+ use temporal_client::{ClientInitError, ConfiguredClient, TemporalServiceClientWithMetrics};
15
+ use temporal_sdk_core::ephemeral_server::EphemeralServer as CoreEphemeralServer;
16
+ use temporal_sdk_core::{
17
+ fetch_global_buffered_logs, init_replay_worker, init_worker,
18
+ protos::temporal::api::history::v1::History, telemetry_init, ClientOptions, RetryClient,
19
+ WorkerConfig,
20
+ };
21
+ use tokio::{
22
+ runtime::Runtime,
23
+ sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
24
+ sync::Mutex,
25
+ };
26
+
27
+ pub type RawClient = RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>;
28
+
29
+ #[derive(Clone)]
30
+ pub struct EphemeralServer {
31
+ pub(crate) runtime: Arc<RuntimeHandle>,
32
+ pub(crate) core_server: Arc<Mutex<CoreEphemeralServer>>,
33
+ }
34
+ pub type BoxedEphemeralServer = JsBox<RefCell<Option<EphemeralServer>>>;
35
+ impl Finalize for EphemeralServer {}
36
+
37
+ pub struct RuntimeHandle {
38
+ pub(crate) sender: UnboundedSender<RuntimeRequest>,
39
+ }
40
+
41
+ /// Box it so we can use the runtime from JS
42
+ pub type BoxedRuntime = JsBox<Arc<RuntimeHandle>>;
43
+ impl Finalize for RuntimeHandle {}
44
+
45
+ #[derive(Clone)]
46
+ pub struct Client {
47
+ pub(crate) runtime: Arc<RuntimeHandle>,
48
+ pub(crate) core_client: Arc<RawClient>,
49
+ }
50
+
51
+ pub type BoxedClient = JsBox<RefCell<Option<Client>>>;
52
+ impl Finalize for Client {}
53
+
54
+ /// A request from JS to bridge to core
55
+ pub enum RuntimeRequest {
56
+ /// A request to shutdown the runtime, breaks from the thread loop.
57
+ Shutdown {
58
+ /// Used to send the result back into JS
59
+ callback: Root<JsFunction>,
60
+ },
61
+ /// A request to create a client in a runtime
62
+ CreateClient {
63
+ runtime: Arc<RuntimeHandle>,
64
+ options: ClientOptions,
65
+ headers: Option<HashMap<String, String>>,
66
+ /// Used to send the result back into JS
67
+ callback: Root<JsFunction>,
68
+ },
69
+ /// A request to update a client's HTTP request headers
70
+ UpdateClientHeaders {
71
+ client: Arc<RawClient>,
72
+ headers: HashMap<String, String>,
73
+ /// Used to send the result back into JS
74
+ callback: Root<JsFunction>,
75
+ },
76
+ /// A request to create a new Worker using a connected client
77
+ InitWorker {
78
+ /// Worker configuration e.g. limits and task queue
79
+ config: WorkerConfig,
80
+ /// A client created with a [CreateClient] request
81
+ client: Arc<RawClient>,
82
+ /// Used to send the result back into JS
83
+ callback: Root<JsFunction>,
84
+ },
85
+ /// A request to register a replay worker
86
+ InitReplayWorker {
87
+ /// Worker configuration. Must have unique task queue name.
88
+ config: WorkerConfig,
89
+ /// The history this worker should replay
90
+ history: History,
91
+ /// Used to send the result back into JS
92
+ callback: Root<JsFunction>,
93
+ },
94
+ /// A request to drain logs from core so they can be emitted in node
95
+ PollLogs {
96
+ /// Logs are sent to this function
97
+ callback: Root<JsFunction>,
98
+ },
99
+ StartEphemeralServer {
100
+ runtime: Arc<RuntimeHandle>,
101
+ config: EphemeralServerConfig,
102
+ callback: Root<JsFunction>,
103
+ },
104
+ ShutdownEphemeralServer {
105
+ server: Arc<Mutex<CoreEphemeralServer>>,
106
+ callback: Root<JsFunction>,
107
+ },
108
+ }
109
+
110
+ /// Inits a multi-threaded tokio runtime used to interact with sdk-core APIs
111
+ pub fn tokio_runtime() -> Runtime {
112
+ tokio::runtime::Builder::new_multi_thread()
113
+ .enable_all()
114
+ .thread_name("core")
115
+ .build()
116
+ .expect("Tokio runtime must construct properly")
117
+ }
118
+
119
+ /// Builds a tokio runtime and starts polling on [RuntimeRequest]s via an internal channel.
120
+ /// Bridges requests from JS to core and sends responses back to JS using a neon::Channel.
121
+ /// Blocks current thread until a [Shutdown] request is received in channel.
122
+ pub fn start_bridge_loop(channel: Arc<Channel>, receiver: &mut UnboundedReceiver<RuntimeRequest>) {
123
+ tokio_runtime().block_on(async {
124
+ loop {
125
+ let request_option = receiver.recv().await;
126
+ let request = match request_option {
127
+ None => break,
128
+ Some(request) => request,
129
+ };
130
+
131
+ let channel = channel.clone();
132
+
133
+ match request {
134
+ RuntimeRequest::Shutdown { callback } => {
135
+ send_result(channel, callback, |cx| Ok(cx.undefined()));
136
+ break;
137
+ }
138
+ RuntimeRequest::CreateClient {
139
+ runtime,
140
+ options,
141
+ headers,
142
+ callback,
143
+ } => {
144
+ // `metrics_meter` (second arg) can be None here since we don't use the
145
+ // returned client directly at the moment, when we repurpose the client to be
146
+ // used by a Worker, `init_worker` will attach the correct metrics meter for
147
+ // us.
148
+ tokio::spawn(async move {
149
+ match options
150
+ .connect_no_namespace(None, headers.map(|h| Arc::new(RwLock::new(h))))
151
+ .await
152
+ {
153
+ Err(err) => {
154
+ send_error(channel.clone(), callback, |cx| match err {
155
+ ClientInitError::SystemInfoCallError(e) => TRANSPORT_ERROR
156
+ .from_string(
157
+ cx,
158
+ format!("Failed to call GetSystemInfo: {}", e),
159
+ ),
160
+ ClientInitError::TonicTransportError(e) => {
161
+ TRANSPORT_ERROR.from_error(cx, e)
162
+ }
163
+ ClientInitError::InvalidUri(e) => {
164
+ Ok(JsError::type_error(cx, format!("{}", e))?.upcast())
165
+ }
166
+ });
167
+ }
168
+ Ok(client) => {
169
+ send_result(channel.clone(), callback, |cx| {
170
+ Ok(cx.boxed(RefCell::new(Some(Client {
171
+ runtime,
172
+ core_client: Arc::new(client),
173
+ }))))
174
+ });
175
+ }
176
+ }
177
+ });
178
+ }
179
+ RuntimeRequest::UpdateClientHeaders {
180
+ client,
181
+ headers,
182
+ callback,
183
+ } => {
184
+ client.get_client().set_headers(headers);
185
+ send_result(channel.clone(), callback, |cx| Ok(cx.undefined()));
186
+ }
187
+ RuntimeRequest::PollLogs { callback } => {
188
+ let logs = fetch_global_buffered_logs();
189
+ send_result(channel.clone(), callback, |cx| {
190
+ let logarr = cx.empty_array();
191
+ for (i, cl) in logs.into_iter().enumerate() {
192
+ // Not much to do here except for panic when there's an
193
+ // error here.
194
+ let logobj = cx.empty_object();
195
+ let level = cx.string(cl.level.to_string());
196
+ logobj.set(cx, "level", level).unwrap();
197
+ let ts = system_time_to_js(cx, cl.timestamp).unwrap();
198
+ logobj.set(cx, "timestamp", ts).unwrap();
199
+ let msg = cx.string(cl.message);
200
+ logobj.set(cx, "message", msg).unwrap();
201
+ logarr.set(cx, i as u32, logobj).unwrap();
202
+ }
203
+ Ok(logarr)
204
+ });
205
+ }
206
+ RuntimeRequest::InitWorker {
207
+ config,
208
+ client,
209
+ callback,
210
+ } => {
211
+ let client = (*client).clone();
212
+ let worker = init_worker(config, client.into_inner());
213
+ let (tx, rx) = unbounded_channel();
214
+ tokio::spawn(start_worker_loop(worker, rx, channel.clone()));
215
+ send_result(channel.clone(), callback, |cx| {
216
+ Ok(cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx }))))
217
+ });
218
+ }
219
+ RuntimeRequest::InitReplayWorker {
220
+ config,
221
+ history,
222
+ callback,
223
+ } => {
224
+ match init_replay_worker(config, &history) {
225
+ Ok(worker) => {
226
+ let (tx, rx) = unbounded_channel();
227
+ tokio::spawn(start_worker_loop(worker, rx, channel.clone()));
228
+ send_result(channel.clone(), callback, |cx| {
229
+ Ok(cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx }))))
230
+ })
231
+ }
232
+ Err(err) => send_error(channel.clone(), callback, move |cx| {
233
+ UNEXPECTED_ERROR.from_error(cx, err.deref())
234
+ }),
235
+ };
236
+ }
237
+ RuntimeRequest::StartEphemeralServer {
238
+ runtime,
239
+ config,
240
+ callback,
241
+ } => {
242
+ tokio::spawn(async move {
243
+ let result = match config {
244
+ EphemeralServerConfig::TestServer(config) => {
245
+ config.start_server().await
246
+ }
247
+ EphemeralServerConfig::Temporalite(config) => {
248
+ config.start_server().await
249
+ }
250
+ };
251
+ match result {
252
+ Err(err) => {
253
+ let err_str = format!("Failed to start ephemeral server: {}", err);
254
+ send_error(channel.clone(), callback, |cx| {
255
+ UNEXPECTED_ERROR.from_string(cx, err_str)
256
+ });
257
+ }
258
+ Ok(server) => {
259
+ send_result(channel.clone(), callback, |cx| {
260
+ Ok(cx.boxed(RefCell::new(Some(EphemeralServer {
261
+ runtime,
262
+ core_server: Arc::new(Mutex::new(server)),
263
+ }))))
264
+ });
265
+ }
266
+ }
267
+ });
268
+ }
269
+ RuntimeRequest::ShutdownEphemeralServer { server, callback } => {
270
+ tokio::spawn(async move {
271
+ void_future_to_js(
272
+ channel,
273
+ callback,
274
+ async move {
275
+ let mut guard = server.lock().await;
276
+ guard.shutdown().await
277
+ },
278
+ |cx, err| {
279
+ UNEXPECTED_ERROR.from_string(
280
+ cx,
281
+ format!("Failed to start test server: {}", err),
282
+ )
283
+ },
284
+ )
285
+ .await
286
+ });
287
+ }
288
+ }
289
+ }
290
+ })
291
+ }
292
+
293
+ // Below are functions exported to JS
294
+
295
+ /// Convert Rust SystemTime into a JS array with 2 numbers (seconds, nanos)
296
+ pub fn system_time_to_js<'a, C>(cx: &mut C, time: SystemTime) -> NeonResult<Handle<'a, JsArray>>
297
+ where
298
+ C: Context<'a>,
299
+ {
300
+ let nanos = time
301
+ .duration_since(UNIX_EPOCH)
302
+ .unwrap_or(Duration::ZERO)
303
+ .as_nanos();
304
+ let only_nanos = cx.number((nanos % 1_000_000_000) as f64);
305
+ let ts_seconds = cx.number((nanos / 1_000_000_000) as f64);
306
+ let ts = cx.empty_array();
307
+ ts.set(cx, 0, ts_seconds).unwrap();
308
+ ts.set(cx, 1, only_nanos).unwrap();
309
+ Ok(ts)
310
+ }
311
+
312
+ /// Helper to get the current time in nanosecond resolution.
313
+ pub fn get_time_of_day(mut cx: FunctionContext) -> JsResult<JsArray> {
314
+ system_time_to_js(&mut cx, SystemTime::now())
315
+ }
316
+
317
+ /// Initialize Core global telemetry.
318
+ /// 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
+ /// Immediately spawns a poller thread that will block on [RuntimeRequest]s
330
+ pub fn runtime_new(mut cx: FunctionContext) -> JsResult<BoxedRuntime> {
331
+ let channel = Arc::new(cx.channel());
332
+ let (sender, mut receiver) = unbounded_channel::<RuntimeRequest>();
333
+
334
+ std::thread::spawn(move || start_bridge_loop(channel, &mut receiver));
335
+
336
+ Ok(cx.boxed(Arc::new(RuntimeHandle { sender })))
337
+ }
338
+
339
+ /// Shutdown the Core instance and break out of the thread loop
340
+ pub fn runtime_shutdown(mut cx: FunctionContext) -> JsResult<JsUndefined> {
341
+ let runtime = cx.argument::<BoxedRuntime>(0)?;
342
+ let callback = cx.argument::<JsFunction>(1)?;
343
+ let request = RuntimeRequest::Shutdown {
344
+ callback: callback.root(&mut cx),
345
+ };
346
+ if let Err(err) = runtime.sender.send(request) {
347
+ callback_with_unexpected_error(&mut cx, callback, err)?;
348
+ };
349
+ Ok(cx.undefined())
350
+ }
351
+
352
+ /// Request to drain forwarded logs from core
353
+ pub fn poll_logs(mut cx: FunctionContext) -> JsResult<JsUndefined> {
354
+ let runtime = cx.argument::<BoxedRuntime>(0)?;
355
+ let callback = cx.argument::<JsFunction>(1)?;
356
+ let request = RuntimeRequest::PollLogs {
357
+ callback: callback.root(&mut cx),
358
+ };
359
+ if let Err(err) = runtime.sender.send(request) {
360
+ callback_with_unexpected_error(&mut cx, callback, err)?;
361
+ }
362
+ Ok(cx.undefined())
363
+ }
364
+
365
+ /// Create a connected gRPC client which can be used to initialize workers.
366
+ /// Client will be returned in the supplied `callback`.
367
+ pub fn client_new(mut cx: FunctionContext) -> JsResult<JsUndefined> {
368
+ let runtime = cx.argument::<BoxedRuntime>(0)?;
369
+ let opts = cx.argument::<JsObject>(1)?;
370
+ let callback = cx.argument::<JsFunction>(2)?;
371
+
372
+ let client_options = opts.as_client_options(&mut cx)?;
373
+ let headers = match js_optional_getter!(&mut cx, &opts, "metadata", JsObject) {
374
+ None => None,
375
+ Some(h) => Some(
376
+ h.as_hash_map_of_string_to_string(&mut cx)
377
+ .map_err(|reason| {
378
+ cx.throw_type_error::<_, HashMap<String, String>>(format!(
379
+ "Invalid metadata: {}",
380
+ reason
381
+ ))
382
+ .unwrap_err()
383
+ })?,
384
+ ),
385
+ };
386
+
387
+ let request = RuntimeRequest::CreateClient {
388
+ runtime: (**runtime).clone(),
389
+ options: client_options,
390
+ headers,
391
+ callback: callback.root(&mut cx),
392
+ };
393
+ if let Err(err) = runtime.sender.send(request) {
394
+ callback_with_unexpected_error(&mut cx, callback, err)?;
395
+ };
396
+
397
+ Ok(cx.undefined())
398
+ }
399
+
400
+ /// Drop a reference to a Client, once all references are dropped, the Client will be closed.
401
+ pub fn client_close(mut cx: FunctionContext) -> JsResult<JsUndefined> {
402
+ let client = cx.argument::<BoxedClient>(0)?;
403
+ if client.replace(None).is_none() {
404
+ ILLEGAL_STATE_ERROR
405
+ .from_string(&mut cx, "Client already closed")
406
+ .and_then(|err| cx.throw(err))?;
407
+ };
408
+ Ok(cx.undefined())
409
+ }
410
+
411
+ /// Update a Client's HTTP request headers
412
+ pub fn client_update_headers(mut cx: FunctionContext) -> JsResult<JsUndefined> {
413
+ let client = cx.argument::<BoxedClient>(0)?;
414
+ let headers = cx
415
+ .argument::<JsObject>(1)?
416
+ .as_hash_map_of_string_to_string(&mut cx)?;
417
+ let callback = cx.argument::<JsFunction>(2)?;
418
+
419
+ match client.borrow().as_ref() {
420
+ None => {
421
+ callback_with_unexpected_error(&mut cx, callback, "Tried to use closed Client")?;
422
+ }
423
+ Some(client) => {
424
+ let request = RuntimeRequest::UpdateClientHeaders {
425
+ client: client.core_client.clone(),
426
+ headers,
427
+ callback: callback.root(&mut cx),
428
+ };
429
+ if let Err(err) = client.runtime.sender.send(request) {
430
+ callback_with_unexpected_error(&mut cx, callback, err)?;
431
+ };
432
+ }
433
+ }
434
+
435
+ Ok(cx.undefined())
436
+ }
package/src/testing.rs ADDED
@@ -0,0 +1,67 @@
1
+ use crate::conversions::*;
2
+ use crate::errors::*;
3
+ use crate::helpers::*;
4
+ use crate::runtime::{BoxedEphemeralServer, BoxedRuntime, RuntimeRequest};
5
+ use neon::prelude::*;
6
+
7
+ // Below are functions exported to JS
8
+
9
+ /// Start an ephemeral Temporal server
10
+ pub fn start_ephemeral_server(mut cx: FunctionContext) -> JsResult<JsUndefined> {
11
+ let runtime = cx.argument::<BoxedRuntime>(0)?;
12
+ let config = cx.argument::<JsObject>(1)?;
13
+ let sdk_version = cx.argument::<JsString>(2)?.value(&mut cx);
14
+ let callback = cx.argument::<JsFunction>(3)?;
15
+
16
+ let config = config.as_ephemeral_server_config(&mut cx, sdk_version)?;
17
+ let request = RuntimeRequest::StartEphemeralServer {
18
+ runtime: (**runtime).clone(),
19
+ config,
20
+ callback: callback.root(&mut cx),
21
+ };
22
+ if let Err(err) = runtime.sender.send(request) {
23
+ callback_with_unexpected_error(&mut cx, callback, err)?;
24
+ };
25
+
26
+ Ok(cx.undefined())
27
+ }
28
+
29
+ /// Get the ephemeral server "target" (address:port string)
30
+ pub fn get_ephemeral_server_target(mut cx: FunctionContext) -> JsResult<JsString> {
31
+ let server = cx.argument::<BoxedEphemeralServer>(0)?;
32
+ let target = server
33
+ .borrow()
34
+ .as_ref()
35
+ .map(|s| cx.string(s.core_server.blocking_lock().target.to_owned()));
36
+ if target.is_none() {
37
+ ILLEGAL_STATE_ERROR
38
+ .from_string(&mut cx, "Tried to use closed test server")
39
+ .and_then(|err| cx.throw(err))?;
40
+ };
41
+ Ok(target.unwrap())
42
+ }
43
+
44
+ /// Shutdown an ephemeral server - consumes the server
45
+ pub fn shutdown_ephemeral_server(mut cx: FunctionContext) -> JsResult<JsUndefined> {
46
+ let server = cx.argument::<BoxedEphemeralServer>(0)?;
47
+ let callback = cx.argument::<JsFunction>(1)?;
48
+ // Drop the ref
49
+ match server.replace(None) {
50
+ None => {
51
+ callback_with_unexpected_error(&mut cx, callback, "Tried to use closed test server")?;
52
+ }
53
+ Some(server) => {
54
+ if let Err(err) = server
55
+ .runtime
56
+ .sender
57
+ .send(RuntimeRequest::ShutdownEphemeralServer {
58
+ server: server.core_server.clone(),
59
+ callback: callback.root(&mut cx),
60
+ })
61
+ {
62
+ callback_with_unexpected_error(&mut cx, callback, err)?;
63
+ };
64
+ }
65
+ }
66
+ Ok(cx.undefined())
67
+ }