@temporalio/core-bridge 1.10.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +563 -676
- package/Cargo.toml +3 -3
- package/lib/index.d.ts +16 -5
- package/lib/index.js.map +1 -1
- package/lib/worker-tuner.d.ts +57 -0
- package/lib/worker-tuner.js +3 -0
- package/lib/worker-tuner.js.map +1 -0
- 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/.github/workflows/heavy.yml +6 -11
- package/sdk-core/.github/workflows/per-pr.yml +23 -41
- package/sdk-core/Cargo.toml +5 -5
- package/sdk-core/README.md +2 -0
- package/sdk-core/client/Cargo.toml +4 -2
- package/sdk-core/client/src/lib.rs +60 -17
- package/sdk-core/client/src/metrics.rs +1 -1
- package/sdk-core/client/src/proxy.rs +17 -12
- package/sdk-core/client/src/raw.rs +218 -69
- package/sdk-core/client/src/retry.rs +19 -9
- package/sdk-core/core/Cargo.toml +12 -12
- package/sdk-core/core/src/abstractions.rs +3 -3
- package/sdk-core/core/src/core_tests/activity_tasks.rs +2 -1
- package/sdk-core/core/src/core_tests/determinism.rs +1 -1
- package/sdk-core/core/src/core_tests/local_activities.rs +73 -10
- package/sdk-core/core/src/core_tests/queries.rs +2 -1
- package/sdk-core/core/src/core_tests/updates.rs +162 -4
- package/sdk-core/core/src/core_tests/workers.rs +38 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +158 -27
- package/sdk-core/core/src/internal_flags.rs +17 -7
- package/sdk-core/core/src/lib.rs +9 -3
- package/sdk-core/core/src/pollers/poll_buffer.rs +1 -10
- package/sdk-core/core/src/protosext/mod.rs +0 -1
- package/sdk-core/core/src/protosext/protocol_messages.rs +105 -16
- package/sdk-core/core/src/retry_logic.rs +22 -2
- package/sdk-core/core/src/telemetry/otel.rs +44 -12
- package/sdk-core/core/src/test_help/mod.rs +65 -12
- package/sdk-core/core/src/worker/activities/local_activities.rs +1 -4
- package/sdk-core/core/src/worker/activities.rs +3 -4
- package/sdk-core/core/src/worker/client/mocks.rs +7 -6
- package/sdk-core/core/src/worker/client.rs +11 -2
- package/sdk-core/core/src/worker/mod.rs +49 -24
- package/sdk-core/core/src/worker/tuner/resource_based.rs +48 -48
- package/sdk-core/core/src/worker/tuner.rs +124 -4
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +1 -1
- package/sdk-core/core/src/worker/workflow/history_update.rs +11 -2
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +18 -3
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +4 -4
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -0
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -1
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +38 -28
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +4 -2
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +95 -71
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/managed_run.rs +214 -14
- package/sdk-core/core/src/worker/workflow/mod.rs +49 -36
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +1 -2
- package/sdk-core/core-api/src/errors.rs +13 -7
- package/sdk-core/core-api/src/lib.rs +9 -1
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/activity_context.rs +3 -4
- package/sdk-core/sdk/src/lib.rs +96 -49
- package/sdk-core/sdk/src/workflow_context/options.rs +8 -4
- package/sdk-core/sdk/src/workflow_context.rs +53 -49
- package/sdk-core/sdk/src/workflow_future.rs +10 -4
- package/sdk-core/sdk-core-protos/Cargo.toml +4 -3
- package/sdk-core/sdk-core-protos/build.rs +2 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/.github/workflows/build.yaml +18 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/LICENSE +21 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/Makefile +59 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +25 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.gen.yaml +14 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.lock +8 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +9 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +520 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +263 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +173 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +164 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +36 -0
- package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/region/v1/message.proto +22 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +50 -8
- package/sdk-core/sdk-core-protos/protos/api_upstream/.gitmodules +3 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +132 -54
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +177 -81
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +13 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +8 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +10 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +3 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +6 -6
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/enhanced_stack_trace.proto +96 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/user_metadata.proto +49 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +6 -7
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +55 -24
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +7 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +21 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +64 -45
- package/sdk-core/sdk-core-protos/src/history_builder.rs +8 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +40 -10
- package/sdk-core/test-utils/src/canned_histories.rs +1 -1
- package/sdk-core/tests/fuzzy_workflow.rs +4 -2
- package/sdk-core/tests/heavy_tests.rs +3 -3
- package/sdk-core/tests/integ_tests/activity_functions.rs +2 -2
- package/sdk-core/tests/integ_tests/client_tests.rs +234 -6
- package/sdk-core/tests/integ_tests/update_tests.rs +180 -47
- package/sdk-core/tests/integ_tests/worker_tests.rs +32 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +47 -3
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +10 -10
- package/sdk-core/tests/main.rs +1 -0
- package/src/conversions.rs +84 -11
- package/src/runtime.rs +5 -17
- package/src/worker.rs +27 -6
- package/ts/index.ts +24 -5
- package/ts/worker-tuner.ts +71 -0
|
@@ -7,7 +7,7 @@ use std::{
|
|
|
7
7
|
};
|
|
8
8
|
use temporal_client::WorkflowOptions;
|
|
9
9
|
use temporal_sdk::{
|
|
10
|
-
interceptors::WorkerInterceptor, ActContext,
|
|
10
|
+
interceptors::WorkerInterceptor, ActContext, ActivityError, CancellableFuture,
|
|
11
11
|
LocalActivityOptions, WfContext, WorkflowResult,
|
|
12
12
|
};
|
|
13
13
|
use temporal_sdk_core::replay::HistoryForReplay;
|
|
@@ -172,7 +172,7 @@ async fn local_act_retry_timer_backoff() {
|
|
|
172
172
|
Ok(().into())
|
|
173
173
|
});
|
|
174
174
|
worker.register_activity("echo", |_: ActContext, _: String| async {
|
|
175
|
-
Result::<(), _>::Err(anyhow!("Oh no I failed!"))
|
|
175
|
+
Result::<(), _>::Err(anyhow!("Oh no I failed!").into())
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
let run_id = worker
|
|
@@ -223,7 +223,7 @@ async fn cancel_immediate(#[case] cancel_type: ActivityCancellationType) {
|
|
|
223
223
|
tokio::select! {
|
|
224
224
|
_ = tokio::time::sleep(Duration::from_secs(10)) => {},
|
|
225
225
|
_ = ctx.cancelled() => {
|
|
226
|
-
return Err(
|
|
226
|
+
return Err(ActivityError::cancelled())
|
|
227
227
|
}
|
|
228
228
|
_ = manual_cancel_act.cancelled() => {}
|
|
229
229
|
}
|
|
@@ -326,22 +326,22 @@ async fn cancel_after_act_starts(
|
|
|
326
326
|
async move {
|
|
327
327
|
if cancel_on_backoff.is_some() {
|
|
328
328
|
if ctx.is_cancelled() {
|
|
329
|
-
return Err(
|
|
329
|
+
return Err(ActivityError::cancelled());
|
|
330
330
|
}
|
|
331
331
|
// Just fail constantly so we get stuck on the backoff timer
|
|
332
|
-
return Err(anyhow!("Oh no I failed!"));
|
|
332
|
+
return Err(anyhow!("Oh no I failed!").into());
|
|
333
333
|
} else {
|
|
334
334
|
tokio::select! {
|
|
335
335
|
_ = tokio::time::sleep(Duration::from_secs(100)) => {},
|
|
336
336
|
_ = ctx.cancelled() => {
|
|
337
|
-
return Err(
|
|
337
|
+
return Err(ActivityError::cancelled())
|
|
338
338
|
}
|
|
339
339
|
_ = manual_cancel_act.cancelled() => {
|
|
340
340
|
return Ok(())
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
|
-
Err(anyhow!("Oh no I failed!"))
|
|
344
|
+
Err(anyhow!("Oh no I failed!").into())
|
|
345
345
|
}
|
|
346
346
|
});
|
|
347
347
|
|
|
@@ -405,7 +405,7 @@ async fn x_to_close_timeout(#[case] is_schedule: bool) {
|
|
|
405
405
|
tokio::select! {
|
|
406
406
|
_ = tokio::time::sleep(Duration::from_secs(100)) => {},
|
|
407
407
|
_ = ctx.cancelled() => {
|
|
408
|
-
return Err(
|
|
408
|
+
return Err(ActivityError::cancelled())
|
|
409
409
|
}
|
|
410
410
|
};
|
|
411
411
|
Ok(())
|
|
@@ -452,7 +452,7 @@ async fn schedule_to_close_timeout_across_timer_backoff(#[case] cached: bool) {
|
|
|
452
452
|
let num_attempts: &'static _ = Box::leak(Box::new(AtomicU8::new(0)));
|
|
453
453
|
worker.register_activity("echo", move |_: ActContext, _: String| async {
|
|
454
454
|
num_attempts.fetch_add(1, Ordering::Relaxed);
|
|
455
|
-
Result::<(), _>::Err(anyhow!("Oh no I failed!"))
|
|
455
|
+
Result::<(), _>::Err(anyhow!("Oh no I failed!").into())
|
|
456
456
|
});
|
|
457
457
|
|
|
458
458
|
starter.start_with_worker(wf_name, &mut worker).await;
|
|
@@ -528,7 +528,7 @@ async fn timer_backoff_concurrent_with_non_timer_backoff() {
|
|
|
528
528
|
Ok(().into())
|
|
529
529
|
});
|
|
530
530
|
worker.register_activity("echo", |_: ActContext, _: String| async {
|
|
531
|
-
Result::<(), _>::Err(anyhow!("Oh no I failed!"))
|
|
531
|
+
Result::<(), _>::Err(anyhow!("Oh no I failed!").into())
|
|
532
532
|
});
|
|
533
533
|
|
|
534
534
|
starter.start_with_worker(wf_name, &mut worker).await;
|
package/sdk-core/tests/main.rs
CHANGED
package/src/conversions.rs
CHANGED
|
@@ -20,7 +20,9 @@ use temporal_sdk_core::{
|
|
|
20
20
|
TestServerConfigBuilder,
|
|
21
21
|
},
|
|
22
22
|
telemetry::{build_otlp_metric_exporter, start_prometheus_metric_exporter},
|
|
23
|
-
ClientOptions, ClientOptionsBuilder, ClientTlsConfig,
|
|
23
|
+
ClientOptions, ClientOptionsBuilder, ClientTlsConfig, ResourceBasedSlotsOptions,
|
|
24
|
+
ResourceBasedSlotsOptionsBuilder, ResourceSlotOptions, RetryConfig, SlotSupplierOptions,
|
|
25
|
+
TlsConfig, TunerHolderOptionsBuilder, Url,
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
pub enum EphemeralServerConfig {
|
|
@@ -49,7 +51,7 @@ type BoxedMeterMaker = Box<dyn FnOnce() -> Result<Arc<dyn CoreMeter>, String> +
|
|
|
49
51
|
|
|
50
52
|
pub(crate) type TelemOptsRes = (TelemetryOptions, Option<BoxedMeterMaker>);
|
|
51
53
|
|
|
52
|
-
pub trait ObjectHandleConversionsExt {
|
|
54
|
+
pub(crate) trait ObjectHandleConversionsExt {
|
|
53
55
|
fn set_default(&self, cx: &mut FunctionContext, key: &str, value: &str) -> NeonResult<()>;
|
|
54
56
|
fn as_client_options(&self, ctx: &mut FunctionContext) -> NeonResult<ClientOptions>;
|
|
55
57
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemOptsRes>;
|
|
@@ -63,6 +65,11 @@ pub trait ObjectHandleConversionsExt {
|
|
|
63
65
|
&self,
|
|
64
66
|
cx: &mut FunctionContext,
|
|
65
67
|
) -> NeonResult<HashMap<String, String>>;
|
|
68
|
+
fn as_slot_supplier(
|
|
69
|
+
&self,
|
|
70
|
+
cx: &mut FunctionContext,
|
|
71
|
+
rbo: &mut Option<ResourceBasedSlotsOptions>,
|
|
72
|
+
) -> NeonResult<SlotSupplierOptions>;
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
@@ -354,12 +361,6 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
354
361
|
let task_queue = js_value_getter!(cx, self, "taskQueue", JsString);
|
|
355
362
|
let enable_remote_activities =
|
|
356
363
|
js_value_getter!(cx, self, "enableNonLocalActivities", JsBoolean);
|
|
357
|
-
let max_outstanding_activities =
|
|
358
|
-
js_value_getter!(cx, self, "maxConcurrentActivityTaskExecutions", JsNumber) as usize;
|
|
359
|
-
let max_outstanding_local_activities =
|
|
360
|
-
js_value_getter!(cx, self, "maxConcurrentLocalActivityExecutions", JsNumber) as usize;
|
|
361
|
-
let max_outstanding_workflow_tasks =
|
|
362
|
-
js_value_getter!(cx, self, "maxConcurrentWorkflowTaskExecutions", JsNumber) as usize;
|
|
363
364
|
let max_concurrent_wft_polls =
|
|
364
365
|
js_value_getter!(cx, self, "maxConcurrentWorkflowTaskPolls", JsNumber) as usize;
|
|
365
366
|
let max_concurrent_at_polls =
|
|
@@ -401,14 +402,46 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
401
402
|
let nonsticky_to_sticky_poll_ratio =
|
|
402
403
|
js_value_getter!(cx, self, "nonStickyToStickyPollRatio", JsNumber) as f32;
|
|
403
404
|
|
|
405
|
+
let tuner = if let Some(tuner) = js_optional_getter!(cx, self, "tuner", JsObject) {
|
|
406
|
+
let mut tuner_holder = TunerHolderOptionsBuilder::default();
|
|
407
|
+
let mut rbo = None;
|
|
408
|
+
|
|
409
|
+
if let Some(wf_slot_supp) =
|
|
410
|
+
js_optional_getter!(cx, &tuner, "workflowTaskSlotSupplier", JsObject)
|
|
411
|
+
{
|
|
412
|
+
tuner_holder.workflow_slot_options(wf_slot_supp.as_slot_supplier(cx, &mut rbo)?);
|
|
413
|
+
}
|
|
414
|
+
if let Some(act_slot_supp) =
|
|
415
|
+
js_optional_getter!(cx, &tuner, "activityTaskSlotSupplier", JsObject)
|
|
416
|
+
{
|
|
417
|
+
tuner_holder.activity_slot_options(act_slot_supp.as_slot_supplier(cx, &mut rbo)?);
|
|
418
|
+
}
|
|
419
|
+
if let Some(local_act_slot_supp) =
|
|
420
|
+
js_optional_getter!(cx, &tuner, "localActivityTaskSlotSupplier", JsObject)
|
|
421
|
+
{
|
|
422
|
+
tuner_holder.local_activity_slot_options(
|
|
423
|
+
local_act_slot_supp.as_slot_supplier(cx, &mut rbo)?,
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
if let Some(rbo) = rbo {
|
|
427
|
+
tuner_holder.resource_based_options(rbo);
|
|
428
|
+
}
|
|
429
|
+
match tuner_holder.build_tuner_holder() {
|
|
430
|
+
Err(e) => {
|
|
431
|
+
return cx.throw_error(format!("Invalid tuner options: {:?}", e));
|
|
432
|
+
}
|
|
433
|
+
Ok(th) => Arc::new(th),
|
|
434
|
+
}
|
|
435
|
+
} else {
|
|
436
|
+
return cx.throw_error("Missing tuner");
|
|
437
|
+
};
|
|
438
|
+
|
|
404
439
|
match WorkerConfigBuilder::default()
|
|
405
440
|
.worker_build_id(js_value_getter!(cx, self, "buildId", JsString))
|
|
406
441
|
.client_identity_override(Some(js_value_getter!(cx, self, "identity", JsString)))
|
|
407
442
|
.use_worker_versioning(js_value_getter!(cx, self, "useVersioning", JsBoolean))
|
|
408
443
|
.no_remote_activities(!enable_remote_activities)
|
|
409
|
-
.
|
|
410
|
-
.max_outstanding_activities(max_outstanding_activities)
|
|
411
|
-
.max_outstanding_local_activities(max_outstanding_local_activities)
|
|
444
|
+
.tuner(tuner)
|
|
412
445
|
.max_concurrent_wft_polls(max_concurrent_wft_polls)
|
|
413
446
|
.max_concurrent_at_polls(max_concurrent_at_polls)
|
|
414
447
|
.nonsticky_to_sticky_poll_ratio(nonsticky_to_sticky_poll_ratio)
|
|
@@ -533,4 +566,44 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
533
566
|
)),
|
|
534
567
|
}
|
|
535
568
|
}
|
|
569
|
+
|
|
570
|
+
fn as_slot_supplier(
|
|
571
|
+
&self,
|
|
572
|
+
cx: &mut FunctionContext,
|
|
573
|
+
rbo: &mut Option<ResourceBasedSlotsOptions>,
|
|
574
|
+
) -> NeonResult<SlotSupplierOptions> {
|
|
575
|
+
match js_value_getter!(cx, self, "type", JsString).as_str() {
|
|
576
|
+
"fixed-size" => Ok(SlotSupplierOptions::FixedSize {
|
|
577
|
+
slots: js_value_getter!(cx, self, "numSlots", JsNumber) as usize,
|
|
578
|
+
}),
|
|
579
|
+
"resource-based" => {
|
|
580
|
+
let min_slots = js_value_getter!(cx, self, "minimumSlots", JsNumber);
|
|
581
|
+
let max_slots = js_value_getter!(cx, self, "maximumSlots", JsNumber);
|
|
582
|
+
let ramp_throttle = js_value_getter!(cx, self, "rampThrottleMs", JsNumber) as u64;
|
|
583
|
+
if let Some(tuner_opts) = js_optional_getter!(cx, self, "tunerOptions", JsObject) {
|
|
584
|
+
let target_mem =
|
|
585
|
+
js_value_getter!(cx, &tuner_opts, "targetMemoryUsage", JsNumber);
|
|
586
|
+
let target_cpu = js_value_getter!(cx, &tuner_opts, "targetCpuUsage", JsNumber);
|
|
587
|
+
*rbo = Some(
|
|
588
|
+
ResourceBasedSlotsOptionsBuilder::default()
|
|
589
|
+
.target_cpu_usage(target_cpu)
|
|
590
|
+
.target_mem_usage(target_mem)
|
|
591
|
+
.build()
|
|
592
|
+
.expect("Building ResourceBasedSlotsOptions can't fail"),
|
|
593
|
+
)
|
|
594
|
+
} else {
|
|
595
|
+
return cx
|
|
596
|
+
.throw_type_error("Resource based slot supplier requires tunerOptions");
|
|
597
|
+
};
|
|
598
|
+
Ok(SlotSupplierOptions::ResourceBased(
|
|
599
|
+
ResourceSlotOptions::new(
|
|
600
|
+
min_slots as usize,
|
|
601
|
+
max_slots as usize,
|
|
602
|
+
Duration::from_millis(ramp_throttle),
|
|
603
|
+
),
|
|
604
|
+
))
|
|
605
|
+
}
|
|
606
|
+
_ => cx.throw_type_error("Invalid slot supplier type"),
|
|
607
|
+
}
|
|
608
|
+
}
|
|
536
609
|
}
|
package/src/runtime.rs
CHANGED
|
@@ -250,15 +250,12 @@ pub fn start_bridge_loop(
|
|
|
250
250
|
let client = (*client).clone();
|
|
251
251
|
match init_worker(&core_runtime, config, client) {
|
|
252
252
|
Ok(worker) => {
|
|
253
|
-
let (tx, rx) = unbounded_channel();
|
|
254
253
|
core_runtime.tokio_handle().spawn(start_worker_loop(
|
|
255
254
|
worker,
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
channel,
|
|
256
|
+
callback,
|
|
257
|
+
None
|
|
258
258
|
));
|
|
259
|
-
send_result(channel.clone(), callback, |cx| {
|
|
260
|
-
Ok(cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx }))))
|
|
261
|
-
});
|
|
262
259
|
}
|
|
263
260
|
Err(err) => send_error(channel.clone(), callback, move |cx| {
|
|
264
261
|
make_named_error_from_error(cx, UNEXPECTED_ERROR, err.deref())
|
|
@@ -273,21 +270,12 @@ pub fn start_bridge_loop(
|
|
|
273
270
|
let (tunnel, stream) = HistoryForReplayTunnel::new(runtime);
|
|
274
271
|
match init_replay_worker(ReplayWorkerInput::new(config, Box::pin(stream))) {
|
|
275
272
|
Ok(worker) => {
|
|
276
|
-
let (tx, rx) = unbounded_channel();
|
|
277
273
|
core_runtime.tokio_handle().spawn(start_worker_loop(
|
|
278
274
|
worker,
|
|
279
|
-
rx,
|
|
280
275
|
channel.clone(),
|
|
276
|
+
callback,
|
|
277
|
+
Some(tunnel)
|
|
281
278
|
));
|
|
282
|
-
send_result(channel.clone(), callback, |cx| {
|
|
283
|
-
let worker =
|
|
284
|
-
cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx })));
|
|
285
|
-
let tunnel = cx.boxed(tunnel);
|
|
286
|
-
let retme = cx.empty_object();
|
|
287
|
-
retme.set(cx, "worker", worker)?;
|
|
288
|
-
retme.set(cx, "pusher", tunnel)?;
|
|
289
|
-
Ok(retme)
|
|
290
|
-
})
|
|
291
279
|
}
|
|
292
280
|
Err(err) => send_error(channel.clone(), callback, move |cx| {
|
|
293
281
|
make_named_error_from_error(cx, UNEXPECTED_ERROR, err.deref())
|
package/src/worker.rs
CHANGED
|
@@ -18,7 +18,7 @@ use temporal_sdk_core::{
|
|
|
18
18
|
},
|
|
19
19
|
Worker as CoreWorker,
|
|
20
20
|
};
|
|
21
|
-
use tokio::sync::mpsc::{
|
|
21
|
+
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
|
22
22
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
23
23
|
|
|
24
24
|
/// Worker struct, hold a reference for the channel sender responsible for sending requests from
|
|
@@ -70,9 +70,34 @@ pub enum WorkerRequest {
|
|
|
70
70
|
/// Returns when the given channel is dropped.
|
|
71
71
|
pub async fn start_worker_loop(
|
|
72
72
|
worker: CoreWorker,
|
|
73
|
-
rx: UnboundedReceiver<WorkerRequest>,
|
|
74
73
|
channel: Arc<Channel>,
|
|
74
|
+
callback: Root<JsFunction>,
|
|
75
|
+
is_replay: Option<HistoryForReplayTunnel>,
|
|
75
76
|
) {
|
|
77
|
+
if is_replay.is_none() {
|
|
78
|
+
if let Err(e) = worker.validate().await {
|
|
79
|
+
send_error(channel, callback, move |cx| {
|
|
80
|
+
make_named_error_from_error(cx, TRANSPORT_ERROR, e)
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
let (tx, rx) = unbounded_channel();
|
|
86
|
+
// Return the worker after validation has happened
|
|
87
|
+
if let Some(tunnel) = is_replay {
|
|
88
|
+
send_result(channel.clone(), callback, |cx| {
|
|
89
|
+
let worker = cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx })));
|
|
90
|
+
let tunnel = cx.boxed(tunnel);
|
|
91
|
+
let retme = cx.empty_object();
|
|
92
|
+
retme.set(cx, "worker", worker)?;
|
|
93
|
+
retme.set(cx, "pusher", tunnel)?;
|
|
94
|
+
Ok(retme)
|
|
95
|
+
})
|
|
96
|
+
} else {
|
|
97
|
+
send_result(channel.clone(), callback, |cx| {
|
|
98
|
+
Ok(cx.boxed(RefCell::new(Some(WorkerHandle { sender: tx }))))
|
|
99
|
+
});
|
|
100
|
+
}
|
|
76
101
|
UnboundedReceiverStream::new(rx)
|
|
77
102
|
.for_each_concurrent(None, |request| {
|
|
78
103
|
let worker = &worker;
|
|
@@ -158,10 +183,6 @@ async fn handle_poll_workflow_activation_request(
|
|
|
158
183
|
send_error(channel, callback, move |cx| match err {
|
|
159
184
|
PollWfError::ShutDown => make_named_error_from_error(cx, SHUTDOWN_ERROR, err),
|
|
160
185
|
PollWfError::TonicError(_) => make_named_error_from_error(cx, TRANSPORT_ERROR, err),
|
|
161
|
-
PollWfError::AutocompleteError(CompleteWfError::MalformedWorkflowCompletion {
|
|
162
|
-
reason,
|
|
163
|
-
..
|
|
164
|
-
}) => Ok(JsError::type_error(cx, reason)?),
|
|
165
186
|
});
|
|
166
187
|
}
|
|
167
188
|
}
|
package/ts/index.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { LogLevel, Duration } from '@temporalio/common';
|
|
2
2
|
import type { TLSConfig, ProxyConfig, HttpConnectProxyConfig } from '@temporalio/common/lib/internal-non-workflow';
|
|
3
|
+
import { WorkerTuner } from './worker-tuner';
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
WorkerTuner,
|
|
7
|
+
SlotSupplier,
|
|
8
|
+
ResourceBasedSlotOptions,
|
|
9
|
+
ResourceBasedTunerOptions,
|
|
10
|
+
FixedSizeSlotSupplier,
|
|
11
|
+
} from './worker-tuner';
|
|
3
12
|
|
|
4
13
|
export type { TLSConfig, ProxyConfig, HttpConnectProxyConfig };
|
|
5
14
|
|
|
@@ -287,9 +296,11 @@ export interface WorkerOptions {
|
|
|
287
296
|
*/
|
|
288
297
|
taskQueue: string;
|
|
289
298
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
299
|
+
/**
|
|
300
|
+
* The tuner the worker will use
|
|
301
|
+
*/
|
|
302
|
+
tuner: WorkerTuner;
|
|
303
|
+
|
|
293
304
|
nonStickyToStickyPollRatio: number;
|
|
294
305
|
|
|
295
306
|
/**
|
|
@@ -410,12 +421,16 @@ export interface TimeSkippingServerConfig {
|
|
|
410
421
|
port?: number;
|
|
411
422
|
/**
|
|
412
423
|
* Extra args to pass to the executable command.
|
|
424
|
+
*
|
|
425
|
+
* Note that the Test Server implementation may be changed to another one in the future. Therefore, there is
|
|
426
|
+
* no guarantee that server options, and particularly those provided through the `extraArgs` array, will continue to
|
|
427
|
+
* be supported in the future.
|
|
413
428
|
*/
|
|
414
429
|
extraArgs?: string[];
|
|
415
430
|
}
|
|
416
431
|
|
|
417
432
|
/**
|
|
418
|
-
* Configuration for the Temporal CLI
|
|
433
|
+
* Configuration for the Temporal CLI Dev Server.
|
|
419
434
|
*/
|
|
420
435
|
export interface DevServerConfig {
|
|
421
436
|
type: 'dev-server';
|
|
@@ -453,6 +468,10 @@ export interface DevServerConfig {
|
|
|
453
468
|
port?: number;
|
|
454
469
|
/**
|
|
455
470
|
* Extra args to pass to the executable command.
|
|
471
|
+
*
|
|
472
|
+
* Note that the Dev Server implementation may be changed to another one in the future. Therefore, there is no
|
|
473
|
+
* guarantee that Dev Server options, and particularly those provided through the `extraArgs` array, will continue to
|
|
474
|
+
* be supported in the future.
|
|
456
475
|
*/
|
|
457
476
|
extraArgs?: string[];
|
|
458
477
|
}
|
|
@@ -460,7 +479,7 @@ export interface DevServerConfig {
|
|
|
460
479
|
/**
|
|
461
480
|
* Configuration for spawning an ephemeral Temporal server.
|
|
462
481
|
*
|
|
463
|
-
* Both the time-skipping
|
|
482
|
+
* Both the time-skipping Test Server and Temporal CLI dev server are supported.
|
|
464
483
|
*/
|
|
465
484
|
export type EphemeralServerConfig = TimeSkippingServerConfig | DevServerConfig;
|
|
466
485
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A worker tuner allows the customization of the performance characteristics of workers by
|
|
3
|
+
* controlling how "slots" are handed out for different task types. In order to poll for and then
|
|
4
|
+
* run tasks, a slot must first be reserved by the {@link SlotSupplier} returned by the tuner.
|
|
5
|
+
*
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
export interface WorkerTuner {
|
|
9
|
+
workflowTaskSlotSupplier: SlotSupplier;
|
|
10
|
+
activityTaskSlotSupplier: SlotSupplier;
|
|
11
|
+
localActivityTaskSlotSupplier: SlotSupplier;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Controls how slots are handed out for a specific task type.
|
|
16
|
+
*
|
|
17
|
+
* For now, only {@link ResourceBasedSlotOptions} and {@link FixedSizeSlotSupplier} are supported,
|
|
18
|
+
* but we may add support for custom tuners in the future.
|
|
19
|
+
*
|
|
20
|
+
* @experimental
|
|
21
|
+
*/
|
|
22
|
+
export type SlotSupplier = ResourceBasedSlotsForType | FixedSizeSlotSupplier;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for a specific slot type within a {@link ResourceBasedSlotsForType}
|
|
26
|
+
*
|
|
27
|
+
* @experimental
|
|
28
|
+
*/
|
|
29
|
+
export interface ResourceBasedSlotOptions {
|
|
30
|
+
// Amount of slots that will be issued regardless of any other checks
|
|
31
|
+
minimumSlots: number;
|
|
32
|
+
// Maximum amount of slots permitted
|
|
33
|
+
maximumSlots: number;
|
|
34
|
+
// Minimum time we will wait (after passing the minimum slots number) between handing out new
|
|
35
|
+
// slots in milliseconds.
|
|
36
|
+
rampThrottleMs: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @experimental
|
|
41
|
+
*/
|
|
42
|
+
type ResourceBasedSlotsForType = ResourceBasedSlotOptions & {
|
|
43
|
+
type: 'resource-based';
|
|
44
|
+
tunerOptions: ResourceBasedTunerOptions;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Options for a {@link ResourceBasedTuner} to control target resource usage
|
|
49
|
+
*
|
|
50
|
+
* @experimental
|
|
51
|
+
*/
|
|
52
|
+
export interface ResourceBasedTunerOptions {
|
|
53
|
+
// A value between 0 and 1 that represents the target (system) memory usage. It's not recommended
|
|
54
|
+
// to set this higher than 0.8, since how much memory a workflow may use is not predictable, and
|
|
55
|
+
// you don't want to encounter OOM errors.
|
|
56
|
+
targetMemoryUsage: number;
|
|
57
|
+
// A value between 0 and 1 that represents the target (system) CPU usage. This can be set to 1.0
|
|
58
|
+
// if desired, but it's recommended to leave some headroom for other processes.
|
|
59
|
+
targetCpuUsage: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A fixed-size slot supplier that will never issue more than a fixed number of slots.
|
|
64
|
+
*
|
|
65
|
+
* @experimental
|
|
66
|
+
*/
|
|
67
|
+
export interface FixedSizeSlotSupplier {
|
|
68
|
+
type: 'fixed-size';
|
|
69
|
+
// The maximum number of slots that can be issued
|
|
70
|
+
numSlots: number;
|
|
71
|
+
}
|