@temporalio/core-bridge 1.8.5 → 1.9.0-rc.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 +189 -152
- package/Cargo.toml +1 -0
- package/lib/index.d.ts +17 -44
- package/lib/index.js.map +1 -1
- package/package.json +3 -4
- 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 +4 -0
- package/sdk-core/.github/workflows/per-pr.yml +96 -0
- package/sdk-core/ARCHITECTURE.md +1 -1
- package/sdk-core/Cargo.toml +6 -0
- package/sdk-core/README.md +37 -21
- package/sdk-core/client/Cargo.toml +6 -3
- package/sdk-core/client/src/lib.rs +272 -138
- package/sdk-core/client/src/metrics.rs +68 -57
- package/sdk-core/client/src/raw.rs +191 -45
- package/sdk-core/client/src/retry.rs +20 -0
- package/sdk-core/client/src/worker_registry/mod.rs +264 -0
- package/sdk-core/client/src/workflow_handle/mod.rs +2 -1
- package/sdk-core/core/Cargo.toml +16 -18
- package/sdk-core/core/src/core_tests/child_workflows.rs +7 -7
- package/sdk-core/core/src/core_tests/mod.rs +1 -0
- package/sdk-core/core/src/core_tests/replay_flag.rs +29 -39
- package/sdk-core/core/src/core_tests/updates.rs +73 -0
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +52 -1
- package/sdk-core/core/src/ephemeral_server/mod.rs +34 -11
- package/sdk-core/core/src/internal_flags.rs +7 -1
- package/sdk-core/core/src/lib.rs +19 -36
- package/sdk-core/core/src/protosext/mod.rs +11 -3
- package/sdk-core/core/src/protosext/protocol_messages.rs +102 -0
- package/sdk-core/core/src/replay/mod.rs +100 -48
- package/sdk-core/core/src/telemetry/log_export.rs +161 -28
- package/sdk-core/core/src/telemetry/metrics.rs +869 -248
- package/sdk-core/core/src/telemetry/mod.rs +135 -239
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -31
- package/sdk-core/core/src/test_help/mod.rs +63 -4
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +12 -2
- package/sdk-core/core/src/worker/activities.rs +276 -10
- package/sdk-core/core/src/worker/client/mocks.rs +18 -0
- package/sdk-core/core/src/worker/client.rs +16 -3
- package/sdk-core/core/src/worker/mod.rs +50 -19
- package/sdk-core/core/src/worker/slot_provider.rs +175 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +27 -34
- package/sdk-core/core/src/worker/workflow/history_update.rs +4 -1
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +36 -94
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +34 -22
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +50 -34
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +106 -92
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +22 -21
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +386 -499
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +12 -2
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +33 -26
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +198 -215
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +66 -62
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +88 -119
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +3 -1
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +411 -0
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +26 -25
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +302 -85
- package/sdk-core/core/src/worker/workflow/managed_run.rs +179 -132
- package/sdk-core/core/src/worker/workflow/mod.rs +121 -46
- package/sdk-core/core/src/worker/workflow/run_cache.rs +8 -12
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +45 -38
- package/sdk-core/core-api/Cargo.toml +7 -6
- package/sdk-core/core-api/src/lib.rs +4 -12
- package/sdk-core/core-api/src/telemetry/metrics.rs +334 -0
- package/sdk-core/core-api/src/telemetry.rs +53 -42
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/{.buildkite/docker → docker}/docker-compose.yaml +1 -1
- package/sdk-core/etc/dynamic-config.yaml +11 -1
- package/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +1 -1
- package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +1 -3
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +2 -2
- package/sdk-core/sdk/Cargo.toml +1 -1
- package/sdk-core/sdk/src/lib.rs +85 -7
- package/sdk-core/sdk/src/workflow_context/options.rs +4 -0
- package/sdk-core/sdk/src/workflow_context.rs +43 -15
- package/sdk-core/sdk/src/workflow_future.rs +334 -204
- package/sdk-core/sdk-core-protos/Cargo.toml +2 -2
- package/sdk-core/sdk-core-protos/build.rs +14 -14
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +99 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +56 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.gen.yaml +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +11 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +18 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/annotations.proto +31 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/api/http.proto +379 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/any.proto +162 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/descriptor.proto +1212 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/duration.proto +115 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/empty.proto +51 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/timestamp.proto +144 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/wrappers.proto +123 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/batch/v1/message.proto +3 -5
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/command/v1/message.proto +11 -13
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/common/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/reset.proto +1 -1
- package/sdk-core/{protos/api_upstream/build/tools.go → sdk-core-protos/protos/api_upstream/temporal/api/export/v1/message.proto} +22 -6
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/filter/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/history/v1/message.proto +21 -23
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/namespace/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/request_response.proto +2 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/replication/v1/message.proto +1 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/schedule/v1/message.proto +36 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +13 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -4
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/update/v1/message.proto +1 -1
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/version/v1/message.proto +2 -3
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflow/v1/message.proto +18 -20
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/request_response.proto +84 -32
- package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/workflowservice/v1/service.proto +205 -47
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +57 -0
- package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +27 -0
- package/sdk-core/sdk-core-protos/src/history_builder.rs +67 -2
- package/sdk-core/sdk-core-protos/src/lib.rs +75 -2
- package/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- package/sdk-core/test-utils/Cargo.toml +5 -1
- package/sdk-core/test-utils/src/canned_histories.rs +3 -57
- package/sdk-core/test-utils/src/interceptors.rs +46 -0
- package/sdk-core/test-utils/src/lib.rs +106 -38
- package/sdk-core/tests/integ_tests/metrics_tests.rs +110 -15
- package/sdk-core/tests/integ_tests/queries_tests.rs +174 -3
- package/sdk-core/tests/integ_tests/update_tests.rs +908 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +44 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +4 -4
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +61 -0
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +27 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +1 -0
- package/sdk-core/tests/main.rs +2 -1
- package/sdk-core/tests/runner.rs +15 -2
- package/src/conversions.rs +75 -89
- package/src/helpers.rs +74 -0
- package/src/runtime.rs +17 -6
- package/src/worker.rs +14 -61
- package/ts/index.ts +21 -52
- package/sdk-core/.buildkite/docker/Dockerfile +0 -9
- package/sdk-core/.buildkite/docker/build.sh +0 -5
- package/sdk-core/.buildkite/docker/docker-compose-ci.yaml +0 -27
- package/sdk-core/.buildkite/pipeline.yml +0 -57
- package/sdk-core/.github/workflows/semgrep.yml +0 -25
- package/sdk-core/core/src/worker/workflow/bridge.rs +0 -35
- package/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +0 -215
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/protos/api_upstream/Makefile +0 -80
- package/sdk-core/protos/api_upstream/api-linter.yaml +0 -40
- package/sdk-core/protos/api_upstream/buf.yaml +0 -9
- package/sdk-core/protos/api_upstream/build/go.mod +0 -7
- package/sdk-core/protos/api_upstream/build/go.sum +0 -5
- package/sdk-core/protos/api_upstream/go.mod +0 -6
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +0 -141
- /package/sdk-core/{.buildkite/docker → docker}/docker-compose-telem.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/docker-compose.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.buildkite/pipeline.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/CODEOWNERS +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/publish-docs.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/.github/workflows/trigger-api-go-update.yml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/LICENSE +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/README.md +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/batch_operation.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/command_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/event_type.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/namespace.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/query.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/schedule.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/task_queue.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/update.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/enums/v1/workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/errordetails/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/failure/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/protocol/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/api_upstream/temporal/api/query/v1/message.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/google/rpc/status.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/grpc/health/v1/health.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_result/activity_result.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/activity_task/activity_task.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/child_workflow/child_workflow.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/common/common.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/core_interface.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/external_data/external_data.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/Makefile +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/api-linter.yaml +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/buf.yaml +0 -0
- /package/sdk-core/{protos/api_upstream → sdk-core-protos/protos/testsrv_upstream}/dependencies/gogoproto/gogo.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +0 -0
- /package/sdk-core/{protos → sdk-core-protos/protos}/testsrv_upstream/temporal/api/testservice/v1/service.proto +0 -0
|
@@ -2,7 +2,10 @@ use crate::integ_tests::activity_functions::echo;
|
|
|
2
2
|
use anyhow::anyhow;
|
|
3
3
|
use assert_matches::assert_matches;
|
|
4
4
|
use futures_util::future::join_all;
|
|
5
|
-
use std::
|
|
5
|
+
use std::{
|
|
6
|
+
sync::atomic::{AtomicBool, Ordering},
|
|
7
|
+
time::Duration,
|
|
8
|
+
};
|
|
6
9
|
use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
|
|
7
10
|
use temporal_sdk::{
|
|
8
11
|
ActContext, ActExitValue, ActivityCancelledError, ActivityOptions, CancellableFuture,
|
|
@@ -974,3 +977,43 @@ async fn graceful_shutdown() {
|
|
|
974
977
|
};
|
|
975
978
|
join!(shutdowner, runner);
|
|
976
979
|
}
|
|
980
|
+
|
|
981
|
+
#[tokio::test]
|
|
982
|
+
async fn activity_can_be_cancelled_by_local_timeout() {
|
|
983
|
+
let wf_name = "activity_can_be_cancelled_by_local_timeout";
|
|
984
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
985
|
+
starter
|
|
986
|
+
.worker_config
|
|
987
|
+
.local_timeout_buffer_for_activities(Duration::from_secs(0));
|
|
988
|
+
let mut worker = starter.worker().await;
|
|
989
|
+
worker.register_wf(wf_name.to_owned(), |ctx: WfContext| async move {
|
|
990
|
+
let res = ctx
|
|
991
|
+
.activity(ActivityOptions {
|
|
992
|
+
activity_type: "echo_activity".to_string(),
|
|
993
|
+
start_to_close_timeout: Some(Duration::from_secs(1)),
|
|
994
|
+
input: "hi!".as_json_payload().expect("serializes fine"),
|
|
995
|
+
retry_policy: Some(RetryPolicy {
|
|
996
|
+
maximum_attempts: 1,
|
|
997
|
+
..Default::default()
|
|
998
|
+
}),
|
|
999
|
+
..Default::default()
|
|
1000
|
+
})
|
|
1001
|
+
.await;
|
|
1002
|
+
assert!(res.timed_out().is_some());
|
|
1003
|
+
Ok(().into())
|
|
1004
|
+
});
|
|
1005
|
+
static WAS_CANCELLED: AtomicBool = AtomicBool::new(false);
|
|
1006
|
+
worker.register_activity(
|
|
1007
|
+
"echo_activity",
|
|
1008
|
+
|ctx: ActContext, echo_me: String| async move {
|
|
1009
|
+
// Doesn't heartbeat
|
|
1010
|
+
ctx.cancelled().await;
|
|
1011
|
+
WAS_CANCELLED.store(true, Ordering::Relaxed);
|
|
1012
|
+
Ok(echo_me)
|
|
1013
|
+
},
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
starter.start_with_worker(wf_name, &mut worker).await;
|
|
1017
|
+
worker.run_until_done().await.unwrap();
|
|
1018
|
+
assert!(WAS_CANCELLED.load(Ordering::Relaxed));
|
|
1019
|
+
}
|
|
@@ -25,7 +25,7 @@ async fn cancel_sender(ctx: WfContext) -> WorkflowResult<()> {
|
|
|
25
25
|
Ok(().into())
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
async fn cancel_receiver(
|
|
28
|
+
async fn cancel_receiver(ctx: WfContext) -> WorkflowResult<()> {
|
|
29
29
|
ctx.cancelled().await;
|
|
30
30
|
Ok(().into())
|
|
31
31
|
}
|
|
@@ -4,7 +4,7 @@ use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
|
|
|
4
4
|
use temporal_sdk_core_protos::temporal::api::enums::v1::WorkflowExecutionStatus;
|
|
5
5
|
use temporal_sdk_core_test_utils::CoreWfStarter;
|
|
6
6
|
|
|
7
|
-
async fn cancelled_wf(
|
|
7
|
+
async fn cancelled_wf(ctx: WfContext) -> WorkflowResult<()> {
|
|
8
8
|
let cancelled = tokio::select! {
|
|
9
9
|
_ = ctx.timer(Duration::from_secs(500)) => false,
|
|
10
10
|
_ = ctx.cancelled() => true
|
|
@@ -64,7 +64,7 @@ async fn abandoned_child_bug_repro() {
|
|
|
64
64
|
|
|
65
65
|
worker.register_wf(
|
|
66
66
|
PARENT_WF_TYPE.to_string(),
|
|
67
|
-
move |
|
|
67
|
+
move |ctx: WfContext| async move {
|
|
68
68
|
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
69
69
|
workflow_id: "abandoned-child".to_owned(),
|
|
70
70
|
workflow_type: CHILD_WF_TYPE.to_owned(),
|
|
@@ -89,7 +89,7 @@ async fn abandoned_child_bug_repro() {
|
|
|
89
89
|
Ok(().into())
|
|
90
90
|
},
|
|
91
91
|
);
|
|
92
|
-
worker.register_wf(CHILD_WF_TYPE.to_string(), |
|
|
92
|
+
worker.register_wf(CHILD_WF_TYPE.to_string(), |ctx: WfContext| async move {
|
|
93
93
|
ctx.cancelled().await;
|
|
94
94
|
Ok(WfExitValue::<()>::Cancelled)
|
|
95
95
|
});
|
|
@@ -135,9 +135,9 @@ async fn abandoned_child_resolves_post_cancel() {
|
|
|
135
135
|
|
|
136
136
|
worker.register_wf(
|
|
137
137
|
PARENT_WF_TYPE.to_string(),
|
|
138
|
-
move |
|
|
138
|
+
move |ctx: WfContext| async move {
|
|
139
139
|
let child = ctx.child_workflow(ChildWorkflowOptions {
|
|
140
|
-
workflow_id: "abandoned-child".to_owned(),
|
|
140
|
+
workflow_id: "abandoned-child-resolve-post-cancel".to_owned(),
|
|
141
141
|
workflow_type: CHILD_WF_TYPE.to_owned(),
|
|
142
142
|
parent_close_policy: ParentClosePolicy::Abandon,
|
|
143
143
|
cancel_type: ChildWorkflowCancellationType::Abandon,
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
use std::time::Duration;
|
|
2
|
+
use temporal_client::{WorkflowClientTrait, WorkflowExecutionInfo};
|
|
3
|
+
use temporal_sdk::{WfContext, WorkflowResult};
|
|
4
|
+
use temporal_sdk_core_test_utils::{get_integ_server_options, CoreWfStarter, NAMESPACE};
|
|
5
|
+
|
|
6
|
+
pub async fn eager_wf(_context: WfContext) -> WorkflowResult<()> {
|
|
7
|
+
Ok(().into())
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
#[tokio::test]
|
|
11
|
+
async fn eager_wf_start() {
|
|
12
|
+
let wf_name = "eager_wf_start";
|
|
13
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
14
|
+
starter.workflow_options.enable_eager_workflow_start = true;
|
|
15
|
+
// hang the test if eager task dispatch failed
|
|
16
|
+
starter.workflow_options.task_timeout = Some(Duration::from_secs(1500));
|
|
17
|
+
starter.no_remote_activities();
|
|
18
|
+
let mut worker = starter.worker().await;
|
|
19
|
+
worker.register_wf(wf_name.to_owned(), eager_wf);
|
|
20
|
+
starter.eager_start_with_worker(wf_name, &mut worker).await;
|
|
21
|
+
worker.run_until_done().await.unwrap();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[tokio::test]
|
|
25
|
+
async fn eager_wf_start_different_clients() {
|
|
26
|
+
let wf_name = "eager_wf_start";
|
|
27
|
+
let mut starter = CoreWfStarter::new(wf_name);
|
|
28
|
+
starter.workflow_options.enable_eager_workflow_start = true;
|
|
29
|
+
// hang the test if wf task needs retry
|
|
30
|
+
starter.workflow_options.task_timeout = Some(Duration::from_secs(1500));
|
|
31
|
+
starter.no_remote_activities();
|
|
32
|
+
let mut worker = starter.worker().await;
|
|
33
|
+
worker.register_wf(wf_name.to_owned(), eager_wf);
|
|
34
|
+
|
|
35
|
+
let client = get_integ_server_options()
|
|
36
|
+
.connect(NAMESPACE.to_string(), None, None)
|
|
37
|
+
.await
|
|
38
|
+
.expect("Should connect");
|
|
39
|
+
let w = starter.get_worker().await;
|
|
40
|
+
let res = client
|
|
41
|
+
.start_workflow(
|
|
42
|
+
vec![],
|
|
43
|
+
w.get_config().task_queue.clone(), // task_queue
|
|
44
|
+
wf_name.to_string(), // workflow_id
|
|
45
|
+
wf_name.to_string(), // workflow_type
|
|
46
|
+
None,
|
|
47
|
+
starter.workflow_options.clone(),
|
|
48
|
+
)
|
|
49
|
+
.await
|
|
50
|
+
.unwrap();
|
|
51
|
+
// different clients means no eager_wf_start.
|
|
52
|
+
assert!(res.eager_workflow_task.is_none());
|
|
53
|
+
|
|
54
|
+
//wf task delivered through default path
|
|
55
|
+
worker.started_workflows.lock().push(WorkflowExecutionInfo {
|
|
56
|
+
namespace: NAMESPACE.to_string(),
|
|
57
|
+
workflow_id: wf_name.to_string(),
|
|
58
|
+
run_id: Some(res.run_id.clone()),
|
|
59
|
+
});
|
|
60
|
+
worker.run_until_done().await.unwrap();
|
|
61
|
+
}
|
|
@@ -167,6 +167,19 @@ async fn replay_ok_ending_with_timed_out() {
|
|
|
167
167
|
replay_abrupt_ending(t2).await;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
#[tokio::test]
|
|
171
|
+
async fn replay_shutdown_worker() {
|
|
172
|
+
let t = canned_histories::single_timer("1");
|
|
173
|
+
let func = timers_wf(1);
|
|
174
|
+
let mut worker = replay_sdk_worker([test_hist_to_replay(t)]);
|
|
175
|
+
worker.register_wf(DEFAULT_WORKFLOW_TYPE, func);
|
|
176
|
+
let shutdown_ctr_i = UniqueShutdownWorker::default();
|
|
177
|
+
let shutdown_ctr = shutdown_ctr_i.runs.clone();
|
|
178
|
+
worker.set_worker_interceptor(shutdown_ctr_i);
|
|
179
|
+
worker.run().await.unwrap();
|
|
180
|
+
assert_eq!(shutdown_ctr.lock().len(), 1);
|
|
181
|
+
}
|
|
182
|
+
|
|
170
183
|
#[rstest::rstest]
|
|
171
184
|
#[tokio::test]
|
|
172
185
|
async fn multiple_histories_replay(#[values(false, true)] use_feeder: bool) {
|
|
@@ -188,7 +201,7 @@ async fn multiple_histories_replay(#[values(false, true)] use_feeder: bool) {
|
|
|
188
201
|
};
|
|
189
202
|
let runs_ctr_i = UniqueRunsCounter::default();
|
|
190
203
|
let runs_ctr = runs_ctr_i.runs.clone();
|
|
191
|
-
worker.set_worker_interceptor(
|
|
204
|
+
worker.set_worker_interceptor(runs_ctr_i);
|
|
192
205
|
worker.register_wf("onetimer", one_timer_wf);
|
|
193
206
|
worker.register_wf("seqtimer", seq_timer_wf);
|
|
194
207
|
|
|
@@ -287,6 +300,18 @@ impl WorkerInterceptor for UniqueRunsCounter {
|
|
|
287
300
|
async fn on_workflow_activation_completion(&self, completion: &WorkflowActivationCompletion) {
|
|
288
301
|
self.runs.lock().insert(completion.run_id.clone());
|
|
289
302
|
}
|
|
303
|
+
}
|
|
290
304
|
|
|
291
|
-
|
|
305
|
+
#[derive(Default)]
|
|
306
|
+
struct UniqueShutdownWorker {
|
|
307
|
+
runs: Arc<Mutex<HashSet<String>>>,
|
|
308
|
+
}
|
|
309
|
+
#[async_trait::async_trait(?Send)]
|
|
310
|
+
impl WorkerInterceptor for UniqueShutdownWorker {
|
|
311
|
+
fn on_shutdown(&self, _sdk_worker: &Worker) {
|
|
312
|
+
// Assumed one worker per task queue.
|
|
313
|
+
self.runs
|
|
314
|
+
.lock()
|
|
315
|
+
.insert(_sdk_worker.task_queue().to_string());
|
|
316
|
+
}
|
|
292
317
|
}
|
package/sdk-core/tests/main.rs
CHANGED
|
@@ -14,6 +14,7 @@ mod integ_tests {
|
|
|
14
14
|
mod metrics_tests;
|
|
15
15
|
mod polling_tests;
|
|
16
16
|
mod queries_tests;
|
|
17
|
+
mod update_tests;
|
|
17
18
|
mod visibility_tests;
|
|
18
19
|
mod workflow_tests;
|
|
19
20
|
|
|
@@ -37,7 +38,7 @@ mod integ_tests {
|
|
|
37
38
|
let opts = get_integ_server_options();
|
|
38
39
|
let runtime = CoreRuntime::new_assume_tokio(get_integ_telem_options()).unwrap();
|
|
39
40
|
let mut retrying_client = opts
|
|
40
|
-
.connect_no_namespace(runtime.
|
|
41
|
+
.connect_no_namespace(runtime.telemetry().get_temporal_metric_meter(), None)
|
|
41
42
|
.await
|
|
42
43
|
.unwrap();
|
|
43
44
|
|
package/sdk-core/tests/runner.rs
CHANGED
|
@@ -70,10 +70,19 @@ async fn main() -> Result<(), anyhow::Error> {
|
|
|
70
70
|
ServerKind::TemporalCLI => {
|
|
71
71
|
let config = TemporalDevServerConfigBuilder::default()
|
|
72
72
|
.exe(default_cached_download())
|
|
73
|
+
// TODO: Delete when temporalCLI enables it by default.
|
|
74
|
+
.extra_args(vec![
|
|
75
|
+
"--dynamic-config-value".to_string(),
|
|
76
|
+
"system.enableEagerWorkflowStart=true".to_string(),
|
|
77
|
+
])
|
|
73
78
|
.build()?;
|
|
74
79
|
println!("Using temporal CLI");
|
|
75
80
|
(
|
|
76
|
-
Some(
|
|
81
|
+
Some(
|
|
82
|
+
config
|
|
83
|
+
.start_server_with_output(Stdio::null(), Stdio::null())
|
|
84
|
+
.await?,
|
|
85
|
+
),
|
|
77
86
|
vec![(INTEG_TEMPORAL_DEV_SERVER_USED_ENV_VAR, "true")],
|
|
78
87
|
)
|
|
79
88
|
}
|
|
@@ -83,7 +92,11 @@ async fn main() -> Result<(), anyhow::Error> {
|
|
|
83
92
|
.build()?;
|
|
84
93
|
println!("Using java test server");
|
|
85
94
|
(
|
|
86
|
-
Some(
|
|
95
|
+
Some(
|
|
96
|
+
config
|
|
97
|
+
.start_server_with_output(Stdio::null(), Stdio::null())
|
|
98
|
+
.await?,
|
|
99
|
+
),
|
|
87
100
|
vec![(INTEG_TEST_SERVER_USED_ENV_VAR, "true")],
|
|
88
101
|
)
|
|
89
102
|
}
|
package/src/conversions.rs
CHANGED
|
@@ -5,18 +5,20 @@ use neon::{
|
|
|
5
5
|
prelude::*,
|
|
6
6
|
types::{JsBoolean, JsNumber, JsString},
|
|
7
7
|
};
|
|
8
|
-
use
|
|
9
|
-
use std::{collections::HashMap, net::SocketAddr, str::FromStr, time::Duration};
|
|
8
|
+
use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration};
|
|
10
9
|
use temporal_sdk_core::{
|
|
11
|
-
api::telemetry::{
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
api::telemetry::{Logger, MetricTemporality, TelemetryOptions, TelemetryOptionsBuilder},
|
|
11
|
+
api::{
|
|
12
|
+
telemetry::{
|
|
13
|
+
metrics::CoreMeter, OtelCollectorOptionsBuilder, PrometheusExporterOptionsBuilder,
|
|
14
|
+
},
|
|
15
|
+
worker::{WorkerConfig, WorkerConfigBuilder},
|
|
14
16
|
},
|
|
15
|
-
api::worker::{WorkerConfig, WorkerConfigBuilder},
|
|
16
17
|
ephemeral_server::{
|
|
17
18
|
TemporalDevServerConfig, TemporalDevServerConfigBuilder, TestServerConfig,
|
|
18
19
|
TestServerConfigBuilder,
|
|
19
20
|
},
|
|
21
|
+
telemetry::{build_otlp_metric_exporter, start_prometheus_metric_exporter},
|
|
20
22
|
ClientOptions, ClientOptionsBuilder, ClientTlsConfig, RetryConfig, TlsConfig, Url,
|
|
21
23
|
};
|
|
22
24
|
|
|
@@ -44,7 +46,6 @@ impl ArrayHandleConversionsExt for Handle<'_, JsArray> {
|
|
|
44
46
|
|
|
45
47
|
pub trait ObjectHandleConversionsExt {
|
|
46
48
|
fn set_default(&self, cx: &mut FunctionContext, key: &str, value: &str) -> NeonResult<()>;
|
|
47
|
-
fn as_otel_span_context(&self, ctx: &mut FunctionContext) -> NeonResult<SpanContext>;
|
|
48
49
|
fn as_client_options(&self, ctx: &mut FunctionContext) -> NeonResult<ClientOptions>;
|
|
49
50
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemetryOptions>;
|
|
50
51
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig>;
|
|
@@ -60,19 +61,6 @@ pub trait ObjectHandleConversionsExt {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
63
|
-
fn as_otel_span_context(&self, ctx: &mut FunctionContext) -> NeonResult<SpanContext> {
|
|
64
|
-
let trace_id = js_value_getter!(ctx, self, "traceId", JsString);
|
|
65
|
-
let span_id = js_value_getter!(ctx, self, "spanId", JsString);
|
|
66
|
-
let trace_flags = js_value_getter!(ctx, self, "traceFlags", JsNumber);
|
|
67
|
-
Ok(SpanContext::new(
|
|
68
|
-
TraceId::from_hex(&trace_id).expect("TraceId is valid"),
|
|
69
|
-
SpanId::from_hex(&span_id).expect("SpanId is valid"),
|
|
70
|
-
TraceFlags::new(trace_flags as u8),
|
|
71
|
-
false,
|
|
72
|
-
TraceState::from_str("").expect("Trace state must be valid"),
|
|
73
|
-
))
|
|
74
|
-
}
|
|
75
|
-
|
|
76
64
|
fn as_hash_map_of_string_to_string(
|
|
77
65
|
&self,
|
|
78
66
|
cx: &mut FunctionContext,
|
|
@@ -178,10 +166,11 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
178
166
|
|
|
179
167
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemetryOptions> {
|
|
180
168
|
let mut telemetry_opts = TelemetryOptionsBuilder::default();
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
169
|
+
if js_optional_value_getter!(cx, self, "noTemporalPrefixForMetrics", JsBoolean)
|
|
170
|
+
.unwrap_or_default()
|
|
171
|
+
{
|
|
172
|
+
telemetry_opts.metric_prefix("".to_string());
|
|
173
|
+
}
|
|
185
174
|
|
|
186
175
|
if let Some(ref logging) = js_optional_getter!(cx, self, "logging", JsObject) {
|
|
187
176
|
let filter = js_value_getter!(cx, logging, "filter", JsString);
|
|
@@ -197,52 +186,72 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
197
186
|
}
|
|
198
187
|
|
|
199
188
|
if let Some(ref metrics) = js_optional_getter!(cx, self, "metrics", JsObject) {
|
|
200
|
-
if let Some(temporality) =
|
|
201
|
-
js_optional_value_getter!(cx, metrics, "temporality", JsString)
|
|
202
|
-
{
|
|
203
|
-
match temporality.as_str() {
|
|
204
|
-
"cumulative" => {
|
|
205
|
-
telemetry_opts.metric_temporality(MetricTemporality::Cumulative);
|
|
206
|
-
}
|
|
207
|
-
"delta" => {
|
|
208
|
-
telemetry_opts.metric_temporality(MetricTemporality::Delta);
|
|
209
|
-
}
|
|
210
|
-
_ => {
|
|
211
|
-
cx.throw_type_error("Invalid telemetryOptions.metrics.temporality, expected 'cumulative' or 'delta'")?;
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
189
|
if let Some(ref prom) = js_optional_getter!(cx, metrics, "prometheus", JsObject) {
|
|
190
|
+
if js_optional_getter!(cx, metrics, "otel", JsObject).is_some() {
|
|
191
|
+
cx.throw_type_error(
|
|
192
|
+
"Invalid telemetryOptions.metrics: can't have both premetheus and otel at the same time",
|
|
193
|
+
)?
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let mut options = PrometheusExporterOptionsBuilder::default();
|
|
197
|
+
|
|
216
198
|
let addr = js_value_getter!(cx, prom, "bindAddress", JsString);
|
|
217
199
|
match addr.parse::<SocketAddr>() {
|
|
218
|
-
Ok(
|
|
219
|
-
Err(_) =>
|
|
220
|
-
|
|
221
|
-
|
|
200
|
+
Ok(addr) => options.socket_addr(addr),
|
|
201
|
+
Err(_) => {
|
|
202
|
+
return cx.throw_type_error(
|
|
203
|
+
"Invalid telemetryOptions.metrics.prometheus.bindAddress",
|
|
204
|
+
)?
|
|
205
|
+
}
|
|
222
206
|
};
|
|
207
|
+
|
|
208
|
+
let options = options
|
|
209
|
+
.build()
|
|
210
|
+
.expect("Failed to build prometheus exporter options");
|
|
211
|
+
let prom_info = start_prometheus_metric_exporter(options)
|
|
212
|
+
.expect("Failed creating prometheus exporter");
|
|
213
|
+
telemetry_opts.metrics(prom_info.meter as Arc<dyn CoreMeter>);
|
|
223
214
|
} else if let Some(ref otel) = js_optional_getter!(cx, metrics, "otel", JsObject) {
|
|
215
|
+
let mut options = OtelCollectorOptionsBuilder::default();
|
|
216
|
+
|
|
224
217
|
let url = js_value_getter!(cx, otel, "url", JsString);
|
|
225
|
-
|
|
226
|
-
Ok(url) => url,
|
|
227
|
-
Err(_) =>
|
|
218
|
+
match Url::parse(&url) {
|
|
219
|
+
Ok(url) => options.url(url),
|
|
220
|
+
Err(_) => {
|
|
221
|
+
return cx.throw_type_error("Invalid telemetryOptions.metrics.otel.url")
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
if let Some(ref headers) = js_optional_getter!(cx, otel, "headers", JsObject) {
|
|
226
|
+
options.headers(headers.as_hash_map_of_string_to_string(cx)?);
|
|
228
227
|
};
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
228
|
+
|
|
229
|
+
if let Some(metric_periodicity) =
|
|
230
|
+
js_optional_value_getter!(cx, otel, "metricsExportInterval", JsNumber)
|
|
231
|
+
.map(|f| f as u64)
|
|
232
|
+
{
|
|
233
|
+
options.metric_periodicity(Duration::from_millis(metric_periodicity));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// FIXME: Move temporality to the otel object
|
|
237
|
+
if let Some(temporality) =
|
|
238
|
+
js_optional_value_getter!(cx, metrics, "temporality", JsString)
|
|
239
|
+
{
|
|
240
|
+
match temporality.as_str() {
|
|
241
|
+
"cumulative" => options.metric_temporality(MetricTemporality::Cumulative),
|
|
242
|
+
"delta" => options.metric_temporality(MetricTemporality::Delta),
|
|
243
|
+
_ => {
|
|
244
|
+
return cx.throw_type_error("Invalid telemetryOptions.metrics.temporality, expected 'cumulative' or 'delta'");
|
|
245
|
+
}
|
|
234
246
|
};
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
headers,
|
|
244
|
-
metric_periodicity,
|
|
245
|
-
}));
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
let options = options
|
|
250
|
+
.build()
|
|
251
|
+
.expect("Failed to build otlp exporter options");
|
|
252
|
+
let otlp_exporter =
|
|
253
|
+
build_otlp_metric_exporter(options).expect("Failed to build otlp exporter");
|
|
254
|
+
telemetry_opts.metrics(Arc::new(otlp_exporter) as Arc<dyn CoreMeter>);
|
|
246
255
|
} else {
|
|
247
256
|
cx.throw_type_error(
|
|
248
257
|
"Invalid telemetryOptions.metrics, missing `prometheus` or `otel` option",
|
|
@@ -250,33 +259,6 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
250
259
|
}
|
|
251
260
|
}
|
|
252
261
|
|
|
253
|
-
if let Some(ref tracing) = js_optional_getter!(cx, self, "tracing", JsObject) {
|
|
254
|
-
let filter = js_value_getter!(cx, tracing, "filter", JsString);
|
|
255
|
-
if let Some(ref otel) = js_optional_getter!(cx, tracing, "otel", JsObject) {
|
|
256
|
-
let url = js_value_getter!(cx, otel, "url", JsString);
|
|
257
|
-
let url = match Url::parse(&url) {
|
|
258
|
-
Ok(url) => url,
|
|
259
|
-
Err(_) => cx.throw_type_error("Invalid telemetryOptions.tracing.otel.url")?,
|
|
260
|
-
};
|
|
261
|
-
let headers =
|
|
262
|
-
if let Some(ref headers) = js_optional_getter!(cx, otel, "headers", JsObject) {
|
|
263
|
-
headers.as_hash_map_of_string_to_string(cx)?
|
|
264
|
-
} else {
|
|
265
|
-
Default::default()
|
|
266
|
-
};
|
|
267
|
-
telemetry_opts.tracing(TraceExportConfig {
|
|
268
|
-
filter,
|
|
269
|
-
exporter: TraceExporter::Otel(OtelCollectorOptions {
|
|
270
|
-
url,
|
|
271
|
-
headers,
|
|
272
|
-
metric_periodicity: None,
|
|
273
|
-
}),
|
|
274
|
-
});
|
|
275
|
-
} else {
|
|
276
|
-
cx.throw_type_error("Invalid telemetryOptions.tracing, missing `otel` option")?
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
262
|
telemetry_opts.build().map_err(|reason| {
|
|
281
263
|
cx.throw_type_error::<_, TelemetryOptions>(format!("{}", reason))
|
|
282
264
|
.unwrap_err()
|
|
@@ -332,6 +314,9 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
332
314
|
js_optional_getter!(cx, self, "shutdownGraceTimeMs", JsNumber)
|
|
333
315
|
.map(|num| Duration::from_millis(num.value(cx) as u64));
|
|
334
316
|
|
|
317
|
+
let nonsticky_to_sticky_poll_ratio =
|
|
318
|
+
js_value_getter!(cx, self, "nonStickyToStickyPollRatio", JsNumber) as f32;
|
|
319
|
+
|
|
335
320
|
match WorkerConfigBuilder::default()
|
|
336
321
|
.worker_build_id(js_value_getter!(cx, self, "buildId", JsString))
|
|
337
322
|
.client_identity_override(Some(js_value_getter!(cx, self, "identity", JsString)))
|
|
@@ -342,6 +327,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
342
327
|
.max_outstanding_local_activities(max_outstanding_local_activities)
|
|
343
328
|
.max_concurrent_wft_polls(max_concurrent_wft_polls)
|
|
344
329
|
.max_concurrent_at_polls(max_concurrent_at_polls)
|
|
330
|
+
.nonsticky_to_sticky_poll_ratio(nonsticky_to_sticky_poll_ratio)
|
|
345
331
|
.max_cached_workflows(max_cached_workflows)
|
|
346
332
|
.sticky_queue_schedule_to_start_timeout(sticky_queue_schedule_to_start_timeout)
|
|
347
333
|
.graceful_shutdown_period(graceful_shutdown_period)
|
package/src/helpers.rs
CHANGED
|
@@ -187,3 +187,77 @@ where
|
|
|
187
187
|
cx.throw_type_error::<_, Vec<u8>>(format!("Invalid or missing {}", full_attr_path))
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
+
|
|
191
|
+
// Recursively convert a Serde value to a JS value
|
|
192
|
+
pub fn serde_value_to_js_value<'a>(
|
|
193
|
+
cx: &mut impl Context<'a>,
|
|
194
|
+
val: serde_json::Value,
|
|
195
|
+
) -> JsResult<'a, JsValue> {
|
|
196
|
+
match val {
|
|
197
|
+
serde_json::Value::String(s) => Ok(cx.string(s).upcast()),
|
|
198
|
+
serde_json::Value::Number(n) => Ok(cx.number(n.as_f64().unwrap()).upcast()),
|
|
199
|
+
serde_json::Value::Bool(b) => Ok(cx.boolean(b).upcast()),
|
|
200
|
+
serde_json::Value::Null => Ok(cx.null().upcast()),
|
|
201
|
+
serde_json::Value::Array(vec) => {
|
|
202
|
+
let arr: Handle<'a, JsArray> = JsArray::new(cx, vec.len() as u32);
|
|
203
|
+
for (i, v) in vec.into_iter().enumerate() {
|
|
204
|
+
let v = serde_value_to_js_value(cx, v)?;
|
|
205
|
+
arr.set(cx, i as u32, v)?;
|
|
206
|
+
}
|
|
207
|
+
Ok(arr.upcast())
|
|
208
|
+
}
|
|
209
|
+
serde_json::Value::Object(map) => hashmap_to_js_value(cx, map).map(|v| v.upcast()),
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
pub fn hashmap_to_js_value<'a>(
|
|
214
|
+
cx: &mut impl Context<'a>,
|
|
215
|
+
map: impl IntoIterator<Item = (String, serde_json::Value)>,
|
|
216
|
+
) -> JsResult<'a, JsObject> {
|
|
217
|
+
let obj: Handle<'a, JsObject> = cx.empty_object();
|
|
218
|
+
for (k, v) in map {
|
|
219
|
+
let k = cx.string(snake_to_camel(k));
|
|
220
|
+
let v = serde_value_to_js_value(cx, v)?;
|
|
221
|
+
obj.set(cx, k, v)?;
|
|
222
|
+
}
|
|
223
|
+
Ok(obj)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
fn snake_to_camel(input: String) -> String {
|
|
227
|
+
match input.find('_') {
|
|
228
|
+
None => input,
|
|
229
|
+
Some(first) => {
|
|
230
|
+
let mut result = String::with_capacity(input.len());
|
|
231
|
+
if first > 0 {
|
|
232
|
+
result.push_str(&input[..first]);
|
|
233
|
+
}
|
|
234
|
+
let mut capitalize = true;
|
|
235
|
+
for c in input[first + 1..].chars() {
|
|
236
|
+
if c == '_' {
|
|
237
|
+
capitalize = true;
|
|
238
|
+
} else if capitalize {
|
|
239
|
+
result.push(c.to_ascii_uppercase());
|
|
240
|
+
capitalize = false;
|
|
241
|
+
} else {
|
|
242
|
+
result.push(c.to_ascii_lowercase());
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
result
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
#[cfg(test)]
|
|
251
|
+
mod tests {
|
|
252
|
+
use super::*;
|
|
253
|
+
|
|
254
|
+
#[test]
|
|
255
|
+
fn snake_to_camel_works() {
|
|
256
|
+
assert_eq!(snake_to_camel("this_is_a_test".into()), "thisIsATest");
|
|
257
|
+
assert_eq!(snake_to_camel("this___IS_a_TEST".into()), "thisIsATest");
|
|
258
|
+
assert_eq!(
|
|
259
|
+
snake_to_camel("éàç_this_is_a_test".into()),
|
|
260
|
+
"éàçThisIsATest"
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
package/src/runtime.rs
CHANGED
|
@@ -14,8 +14,10 @@ use temporal_client::{ClientInitError, ConfiguredClient, TemporalServiceClientWi
|
|
|
14
14
|
use temporal_sdk_core::api::telemetry::{CoreTelemetry, TelemetryOptions};
|
|
15
15
|
use temporal_sdk_core::CoreRuntime;
|
|
16
16
|
use temporal_sdk_core::{
|
|
17
|
-
ephemeral_server::EphemeralServer as CoreEphemeralServer,
|
|
18
|
-
|
|
17
|
+
ephemeral_server::EphemeralServer as CoreEphemeralServer,
|
|
18
|
+
init_replay_worker, init_worker,
|
|
19
|
+
replay::{HistoryForReplay, ReplayWorkerInput},
|
|
20
|
+
ClientOptions, RetryClient, WorkerConfig,
|
|
19
21
|
};
|
|
20
22
|
use tokio::sync::{
|
|
21
23
|
mpsc::{channel, unbounded_channel, Sender, UnboundedReceiver, UnboundedSender},
|
|
@@ -149,7 +151,7 @@ pub fn start_bridge_loop(
|
|
|
149
151
|
core_runtime.tokio_handle().spawn(async move {
|
|
150
152
|
match options
|
|
151
153
|
.connect_no_namespace(
|
|
152
|
-
runtime_clone.
|
|
154
|
+
runtime_clone.telemetry().get_metric_meter(),
|
|
153
155
|
headers.map(|h| Arc::new(RwLock::new(h))),
|
|
154
156
|
)
|
|
155
157
|
.await
|
|
@@ -195,15 +197,24 @@ pub fn start_bridge_loop(
|
|
|
195
197
|
send_result(channel.clone(), callback, |cx| {
|
|
196
198
|
let logarr = cx.empty_array();
|
|
197
199
|
for (i, cl) in logs.into_iter().enumerate() {
|
|
198
|
-
// Not much to do here except for panic when there's an
|
|
199
|
-
// error here.
|
|
200
|
+
// Not much to do here except for panic when there's an error here.
|
|
200
201
|
let logobj = cx.empty_object();
|
|
202
|
+
|
|
201
203
|
let level = cx.string(cl.level.to_string());
|
|
202
204
|
logobj.set(cx, "level", level).unwrap();
|
|
205
|
+
|
|
203
206
|
let ts = system_time_to_js(cx, cl.timestamp).unwrap();
|
|
204
207
|
logobj.set(cx, "timestamp", ts).unwrap();
|
|
208
|
+
|
|
205
209
|
let msg = cx.string(cl.message);
|
|
206
210
|
logobj.set(cx, "message", msg).unwrap();
|
|
211
|
+
|
|
212
|
+
let fieldsobj = hashmap_to_js_value(cx, cl.fields);
|
|
213
|
+
logobj.set(cx, "fields", fieldsobj.unwrap()).unwrap();
|
|
214
|
+
|
|
215
|
+
let target = cx.string(cl.target);
|
|
216
|
+
logobj.set(cx, "target", target).unwrap();
|
|
217
|
+
|
|
207
218
|
logarr.set(cx, i as u32, logobj).unwrap();
|
|
208
219
|
}
|
|
209
220
|
Ok(logarr)
|
|
@@ -238,7 +249,7 @@ pub fn start_bridge_loop(
|
|
|
238
249
|
callback,
|
|
239
250
|
} => {
|
|
240
251
|
let (tunnel, stream) = HistoryForReplayTunnel::new(runtime);
|
|
241
|
-
match init_replay_worker(config, Box::pin(stream)) {
|
|
252
|
+
match init_replay_worker(ReplayWorkerInput::new(config, Box::pin(stream))) {
|
|
242
253
|
Ok(worker) => {
|
|
243
254
|
let (tx, rx) = unbounded_channel();
|
|
244
255
|
core_runtime.tokio_handle().spawn(start_worker_loop(
|