@temporalio/core-bridge 1.9.2 → 1.10.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 +754 -473
- package/Cargo.toml +3 -3
- package/lib/index.d.ts +33 -2
- package/lib/index.js.map +1 -1
- package/package.json +4 -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/scripts/build.js +4 -3
- package/sdk-core/.cargo/config.toml +2 -4
- package/sdk-core/.github/workflows/heavy.yml +1 -1
- package/sdk-core/.github/workflows/per-pr.yml +6 -4
- package/sdk-core/Cargo.toml +10 -3
- package/sdk-core/README.md +4 -6
- package/sdk-core/client/Cargo.toml +13 -5
- package/sdk-core/client/src/lib.rs +123 -34
- package/sdk-core/client/src/metrics.rs +70 -18
- package/sdk-core/client/src/proxy.rs +85 -0
- package/sdk-core/client/src/raw.rs +67 -5
- package/sdk-core/client/src/worker_registry/mod.rs +5 -3
- package/sdk-core/client/src/workflow_handle/mod.rs +3 -1
- package/sdk-core/core/Cargo.toml +31 -37
- package/sdk-core/core/src/abstractions/take_cell.rs +3 -3
- package/sdk-core/core/src/abstractions.rs +176 -108
- package/sdk-core/core/src/core_tests/activity_tasks.rs +4 -13
- package/sdk-core/core/src/core_tests/determinism.rs +2 -1
- package/sdk-core/core/src/core_tests/local_activities.rs +3 -3
- package/sdk-core/core/src/core_tests/mod.rs +3 -3
- package/sdk-core/core/src/core_tests/queries.rs +42 -5
- package/sdk-core/core/src/core_tests/workers.rs +2 -3
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +115 -15
- package/sdk-core/core/src/ephemeral_server/mod.rs +109 -136
- package/sdk-core/core/src/internal_flags.rs +8 -8
- package/sdk-core/core/src/lib.rs +16 -11
- package/sdk-core/core/src/pollers/mod.rs +11 -5
- package/sdk-core/core/src/pollers/poll_buffer.rs +48 -29
- package/sdk-core/core/src/protosext/mod.rs +32 -32
- package/sdk-core/core/src/protosext/protocol_messages.rs +14 -24
- package/sdk-core/core/src/retry_logic.rs +2 -2
- package/sdk-core/core/src/telemetry/log_export.rs +10 -9
- package/sdk-core/core/src/telemetry/metrics.rs +233 -330
- package/sdk-core/core/src/telemetry/mod.rs +11 -38
- package/sdk-core/core/src/telemetry/otel.rs +355 -0
- package/sdk-core/core/src/telemetry/prometheus_server.rs +36 -23
- package/sdk-core/core/src/test_help/mod.rs +80 -59
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +6 -6
- package/sdk-core/core/src/worker/activities/local_activities.rs +46 -43
- package/sdk-core/core/src/worker/activities.rs +45 -46
- package/sdk-core/core/src/worker/client/mocks.rs +8 -7
- package/sdk-core/core/src/worker/client.rs +40 -39
- package/sdk-core/core/src/worker/mod.rs +72 -42
- package/sdk-core/core/src/worker/slot_provider.rs +28 -28
- package/sdk-core/core/src/worker/slot_supplier.rs +1 -0
- package/sdk-core/core/src/worker/tuner/fixed_size.rs +52 -0
- package/sdk-core/core/src/worker/tuner/resource_based.rs +561 -0
- package/sdk-core/core/src/worker/tuner.rs +122 -0
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +6 -6
- package/sdk-core/core/src/worker/workflow/history_update.rs +27 -53
- package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +4 -17
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -10
- package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +4 -11
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +17 -35
- package/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +0 -8
- package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +1 -5
- package/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +0 -14
- package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +0 -5
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -10
- package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +3 -10
- package/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +12 -8
- package/sdk-core/core/src/worker/workflow/machines/update_state_machine.rs +0 -10
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -13
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +27 -37
- package/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +3 -14
- package/sdk-core/core/src/worker/workflow/managed_run.rs +84 -54
- package/sdk-core/core/src/worker/workflow/mod.rs +63 -160
- package/sdk-core/core/src/worker/workflow/run_cache.rs +22 -13
- package/sdk-core/core/src/worker/workflow/wft_extraction.rs +16 -3
- package/sdk-core/core/src/worker/workflow/wft_poller.rs +15 -12
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +39 -78
- package/sdk-core/core-api/Cargo.toml +6 -5
- package/sdk-core/core-api/src/errors.rs +8 -0
- package/sdk-core/core-api/src/telemetry/metrics.rs +75 -4
- package/sdk-core/core-api/src/telemetry.rs +7 -1
- package/sdk-core/core-api/src/worker.rs +212 -56
- package/sdk-core/fsm/Cargo.toml +3 -0
- package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +1 -1
- package/sdk-core/sdk/Cargo.toml +5 -7
- package/sdk-core/sdk/src/app_data.rs +3 -3
- package/sdk-core/sdk/src/lib.rs +5 -3
- package/sdk-core/sdk/src/workflow_context/options.rs +1 -1
- package/sdk-core/sdk/src/workflow_context.rs +10 -9
- package/sdk-core/sdk/src/workflow_future.rs +1 -1
- package/sdk-core/sdk-core-protos/Cargo.toml +8 -6
- package/sdk-core/sdk-core-protos/build.rs +1 -10
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +3 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/ci.yml +26 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/Makefile +42 -20
- package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/api-linter.yaml +36 -26
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.lock +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/google/protobuf/struct.proto +95 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +9632 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +7337 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/payload_description.txt +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +45 -11
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +22 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/command_type.proto +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +44 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/event_type.proto +18 -3
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +30 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/update.proto +7 -8
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/workflow.proto +23 -5
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/errordetails/v1/message.proto +20 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +25 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +141 -15
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +12 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +193 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +73 -6
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +46 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +4 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto +2 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +116 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +134 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +274 -29
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +57 -1
- package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +10 -12
- package/sdk-core/sdk-core-protos/src/history_builder.rs +1 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +54 -51
- package/sdk-core/sdk-core-protos/src/task_token.rs +11 -2
- package/sdk-core/test-utils/Cargo.toml +7 -4
- package/sdk-core/test-utils/src/histfetch.rs +1 -1
- package/sdk-core/test-utils/src/lib.rs +44 -62
- package/sdk-core/tests/fuzzy_workflow.rs +5 -2
- package/sdk-core/tests/heavy_tests.rs +114 -17
- package/sdk-core/tests/integ_tests/activity_functions.rs +1 -1
- package/sdk-core/tests/integ_tests/client_tests.rs +2 -2
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +38 -26
- package/sdk-core/tests/integ_tests/metrics_tests.rs +126 -17
- package/sdk-core/tests/integ_tests/polling_tests.rs +118 -2
- package/sdk-core/tests/integ_tests/update_tests.rs +3 -5
- package/sdk-core/tests/integ_tests/visibility_tests.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -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 +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +5 -4
- package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -2
- package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +6 -10
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +9 -7
- package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +14 -9
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +6 -13
- package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +9 -6
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +5 -5
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests.rs +115 -11
- package/sdk-core/tests/main.rs +2 -2
- package/src/conversions.rs +57 -0
- package/src/lib.rs +1 -0
- package/src/runtime.rs +51 -35
- package/ts/index.ts +67 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +0 -117
- package/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +0 -24
- package/sdk-core/sdk/src/payload_converter.rs +0 -11
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/Dockerfile +0 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/docker-compose.yml +0 -15
- package/sdk-core/sdk-core-protos/protos/api_upstream/.buildkite/pipeline.yml +0 -10
- package/sdk-core/test-utils/src/wf_input_saver.rs +0 -50
- package/sdk-core/tests/wf_input_replay.rs +0 -32
|
@@ -10,7 +10,10 @@ use crate::{
|
|
|
10
10
|
test_worker_cfg, FakeWfResponses, MockPollCfg, MocksHolder, ResponseType, WorkerExt,
|
|
11
11
|
WorkflowCachingPolicy::{self, AfterEveryReply, NonSticky},
|
|
12
12
|
},
|
|
13
|
-
worker::
|
|
13
|
+
worker::{
|
|
14
|
+
client::mocks::{mock_manual_workflow_client, mock_workflow_client},
|
|
15
|
+
TunerBuilder,
|
|
16
|
+
},
|
|
14
17
|
Worker,
|
|
15
18
|
};
|
|
16
19
|
use futures::{stream, FutureExt};
|
|
@@ -26,7 +29,13 @@ use std::{
|
|
|
26
29
|
};
|
|
27
30
|
use temporal_client::WorkflowOptions;
|
|
28
31
|
use temporal_sdk::{ActivityOptions, CancellableFuture, WfContext};
|
|
29
|
-
use temporal_sdk_core_api::{
|
|
32
|
+
use temporal_sdk_core_api::{
|
|
33
|
+
errors::PollWfError,
|
|
34
|
+
worker::{
|
|
35
|
+
SlotKind, SlotReservationContext, SlotSupplier, SlotSupplierPermit, WorkflowSlotKind,
|
|
36
|
+
},
|
|
37
|
+
Worker as WorkerTrait,
|
|
38
|
+
};
|
|
30
39
|
use temporal_sdk_core_protos::{
|
|
31
40
|
coresdk::{
|
|
32
41
|
activity_result::{self as ar, activity_resolution, ActivityResolution},
|
|
@@ -911,7 +920,7 @@ async fn max_wft_respected() {
|
|
|
911
920
|
let mh = MockPollCfg::new(hists.into_iter().collect(), true, 0);
|
|
912
921
|
let mut worker = mock_sdk_cfg(mh, |cfg| {
|
|
913
922
|
cfg.max_cached_workflows = total_wfs as usize;
|
|
914
|
-
cfg.max_outstanding_workflow_tasks = 1;
|
|
923
|
+
cfg.max_outstanding_workflow_tasks = Some(1);
|
|
915
924
|
});
|
|
916
925
|
let active_count: &'static _ = Box::leak(Box::new(Semaphore::new(1)));
|
|
917
926
|
worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
|
|
@@ -1506,7 +1515,7 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1506
1515
|
let mut mock = build_mock_pollers(mock);
|
|
1507
1516
|
mock.worker_cfg(|cfg| {
|
|
1508
1517
|
cfg.max_cached_workflows = 2;
|
|
1509
|
-
cfg.max_outstanding_workflow_tasks = 2;
|
|
1518
|
+
cfg.max_outstanding_workflow_tasks = Some(2);
|
|
1510
1519
|
});
|
|
1511
1520
|
let outstanding_mock_tasks = mock.outstanding_task_map.clone();
|
|
1512
1521
|
let worker = mock_worker(mock);
|
|
@@ -1531,7 +1540,7 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1531
1540
|
variant: Some(workflow_activation_job::Variant::RemoveFromCache(_)),
|
|
1532
1541
|
},]
|
|
1533
1542
|
);
|
|
1534
|
-
run_id
|
|
1543
|
+
run_id.clone_from(&activation.run_id);
|
|
1535
1544
|
worker
|
|
1536
1545
|
.complete_workflow_activation(WorkflowActivationCompletion::empty(activation.run_id))
|
|
1537
1546
|
.await
|
|
@@ -1546,7 +1555,7 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1546
1555
|
outstanding_mock_tasks.unwrap().release_run(&run_id);
|
|
1547
1556
|
let activation = worker.poll_workflow_activation().await.unwrap();
|
|
1548
1557
|
// There should be no change in permits, since this just unbuffered the buffered task
|
|
1549
|
-
assert_eq!(worker.available_wft_permits(), 1);
|
|
1558
|
+
assert_eq!(worker.available_wft_permits(), Some(1));
|
|
1550
1559
|
worker
|
|
1551
1560
|
.complete_workflow_activation(WorkflowActivationCompletion::from_cmd(
|
|
1552
1561
|
activation.run_id,
|
|
@@ -1555,7 +1564,7 @@ async fn failing_wft_doesnt_eat_permit_forever() {
|
|
|
1555
1564
|
.await
|
|
1556
1565
|
.unwrap();
|
|
1557
1566
|
worker.shutdown().await;
|
|
1558
|
-
assert_eq!(worker.available_wft_permits(), 2);
|
|
1567
|
+
assert_eq!(worker.available_wft_permits(), Some(2));
|
|
1559
1568
|
}
|
|
1560
1569
|
|
|
1561
1570
|
#[tokio::test]
|
|
@@ -1582,7 +1591,7 @@ async fn cache_miss_will_fetch_history() {
|
|
|
1582
1591
|
mock.worker_cfg(|cfg| {
|
|
1583
1592
|
cfg.max_cached_workflows = 1;
|
|
1584
1593
|
// Also verifies tying the WFT permit to the fetch request doesn't get us stuck
|
|
1585
|
-
cfg.max_outstanding_workflow_tasks = 1;
|
|
1594
|
+
cfg.max_outstanding_workflow_tasks = Some(1);
|
|
1586
1595
|
});
|
|
1587
1596
|
let worker = mock_worker(mock);
|
|
1588
1597
|
|
|
@@ -1808,7 +1817,7 @@ async fn poll_faster_than_complete_wont_overflow_cache() {
|
|
|
1808
1817
|
let mut mock = build_mock_pollers(mock_cfg);
|
|
1809
1818
|
mock.worker_cfg(|wc| {
|
|
1810
1819
|
wc.max_cached_workflows = 3;
|
|
1811
|
-
wc.max_outstanding_workflow_tasks = 3;
|
|
1820
|
+
wc.max_outstanding_workflow_tasks = Some(3);
|
|
1812
1821
|
});
|
|
1813
1822
|
let core = mock_worker(mock);
|
|
1814
1823
|
// Poll 4 times, completing once, such that max tasks are never exceeded
|
|
@@ -1915,7 +1924,7 @@ async fn poll_faster_than_complete_wont_overflow_cache() {
|
|
|
1915
1924
|
|
|
1916
1925
|
join!(blocking_poll, complete_evict);
|
|
1917
1926
|
// p5 outstanding and final poll outstanding -- hence one permit available
|
|
1918
|
-
assert_eq!(core.available_wft_permits(), 1);
|
|
1927
|
+
assert_eq!(core.available_wft_permits(), Some(1));
|
|
1919
1928
|
assert_eq!(core.cached_workflows().await, 3);
|
|
1920
1929
|
}
|
|
1921
1930
|
|
|
@@ -2663,8 +2672,8 @@ async fn poller_wont_run_ahead_of_task_slots() {
|
|
|
2663
2672
|
}
|
|
2664
2673
|
|
|
2665
2674
|
assert_eq!(worker.outstanding_workflow_tasks().await, 10);
|
|
2666
|
-
assert_eq!(worker.available_wft_permits(), 0);
|
|
2667
|
-
assert_eq!(worker.unused_wft_permits(), 0);
|
|
2675
|
+
assert_eq!(worker.available_wft_permits(), Some(0));
|
|
2676
|
+
assert_eq!(worker.unused_wft_permits(), Some(0));
|
|
2668
2677
|
|
|
2669
2678
|
// This one should hang until we complete some tasks since we're at the limit
|
|
2670
2679
|
let hung_poll = async {
|
|
@@ -2752,13 +2761,13 @@ async fn use_compatible_version_flag(
|
|
|
2752
2761
|
let can_cmd = c.commands.pop().unwrap().attributes.unwrap();
|
|
2753
2762
|
match can_cmd {
|
|
2754
2763
|
Attributes::ContinueAsNewWorkflowExecutionCommandAttributes(a) => {
|
|
2755
|
-
assert_eq!(a.
|
|
2764
|
+
assert_eq!(a.inherit_build_id, compat_flag_expected);
|
|
2756
2765
|
}
|
|
2757
2766
|
Attributes::ScheduleActivityTaskCommandAttributes(a) => {
|
|
2758
|
-
assert_eq!(a.
|
|
2767
|
+
assert_eq!(a.use_workflow_build_id, compat_flag_expected);
|
|
2759
2768
|
}
|
|
2760
2769
|
Attributes::StartChildWorkflowExecutionCommandAttributes(a) => {
|
|
2761
|
-
assert_eq!(a.
|
|
2770
|
+
assert_eq!(a.inherit_build_id, compat_flag_expected);
|
|
2762
2771
|
}
|
|
2763
2772
|
_ => panic!("invalid attributes type"),
|
|
2764
2773
|
}
|
|
@@ -2855,3 +2864,94 @@ async fn sets_build_id_from_wft_complete() {
|
|
|
2855
2864
|
.unwrap();
|
|
2856
2865
|
worker.run_until_done().await.unwrap();
|
|
2857
2866
|
}
|
|
2867
|
+
|
|
2868
|
+
#[tokio::test]
|
|
2869
|
+
async fn slot_provider_cant_hand_out_more_permits_than_cache_size() {
|
|
2870
|
+
let popped_tasks = Arc::new(AtomicUsize::new(0));
|
|
2871
|
+
let ptc = popped_tasks.clone();
|
|
2872
|
+
let mut bunch_of_first_tasks = (1..50).map(move |i| {
|
|
2873
|
+
ptc.fetch_add(1, Ordering::Relaxed);
|
|
2874
|
+
hist_to_poll_resp(
|
|
2875
|
+
&canned_histories::single_timer(&format!("{i}")),
|
|
2876
|
+
format!("wf-{i}"),
|
|
2877
|
+
1.into(),
|
|
2878
|
+
)
|
|
2879
|
+
.resp
|
|
2880
|
+
});
|
|
2881
|
+
let mut mock_client = mock_workflow_client();
|
|
2882
|
+
mock_client
|
|
2883
|
+
.expect_poll_workflow_task()
|
|
2884
|
+
.returning(move |_| Ok(bunch_of_first_tasks.next().unwrap()));
|
|
2885
|
+
mock_client
|
|
2886
|
+
.expect_complete_workflow_task()
|
|
2887
|
+
.returning(|_| Ok(Default::default()));
|
|
2888
|
+
|
|
2889
|
+
struct EndlessSupplier {}
|
|
2890
|
+
#[async_trait::async_trait]
|
|
2891
|
+
impl SlotSupplier for EndlessSupplier {
|
|
2892
|
+
type SlotKind = WorkflowSlotKind;
|
|
2893
|
+
async fn reserve_slot(&self, _: &dyn SlotReservationContext) -> SlotSupplierPermit {
|
|
2894
|
+
SlotSupplierPermit::default()
|
|
2895
|
+
}
|
|
2896
|
+
fn try_reserve_slot(&self, _: &dyn SlotReservationContext) -> Option<SlotSupplierPermit> {
|
|
2897
|
+
Some(SlotSupplierPermit::default())
|
|
2898
|
+
}
|
|
2899
|
+
fn mark_slot_used(&self, _: <Self::SlotKind as SlotKind>::Info<'_>) {}
|
|
2900
|
+
fn release_slot(&self) {}
|
|
2901
|
+
fn available_slots(&self) -> Option<usize> {
|
|
2902
|
+
None
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
let worker = Worker::new_test(
|
|
2907
|
+
test_worker_cfg()
|
|
2908
|
+
.max_cached_workflows(10_usize)
|
|
2909
|
+
.tuner(
|
|
2910
|
+
TunerBuilder::default()
|
|
2911
|
+
.workflow_slot_supplier(Arc::new(EndlessSupplier {}))
|
|
2912
|
+
.build(),
|
|
2913
|
+
)
|
|
2914
|
+
.max_concurrent_wft_polls(10_usize)
|
|
2915
|
+
.no_remote_activities(true)
|
|
2916
|
+
.build()
|
|
2917
|
+
.unwrap(),
|
|
2918
|
+
mock_client,
|
|
2919
|
+
);
|
|
2920
|
+
|
|
2921
|
+
// Should be able to get at 10 tasks
|
|
2922
|
+
let mut tasks = vec![];
|
|
2923
|
+
for _ in 0..10 {
|
|
2924
|
+
tasks.push(worker.poll_workflow_activation().await.unwrap());
|
|
2925
|
+
}
|
|
2926
|
+
// 11th should hang
|
|
2927
|
+
|
|
2928
|
+
assert_eq!(worker.outstanding_workflow_tasks().await, 10);
|
|
2929
|
+
// assert_eq!(worker.available_wft_permits(), Some(0));
|
|
2930
|
+
// assert_eq!(worker.unused_wft_permits(), Some(0));
|
|
2931
|
+
|
|
2932
|
+
// This one should hang until we complete some tasks since we're at the limit
|
|
2933
|
+
let hung_poll = async {
|
|
2934
|
+
// This should end up getting shut down after the other routine finishes tasks
|
|
2935
|
+
assert_matches!(
|
|
2936
|
+
worker.poll_workflow_activation().await.unwrap_err(),
|
|
2937
|
+
PollWfError::ShutDown
|
|
2938
|
+
);
|
|
2939
|
+
};
|
|
2940
|
+
// Wait for a bit concurrently with above, verify no extra tasks got taken, shutdown
|
|
2941
|
+
let ender = async {
|
|
2942
|
+
time::sleep(Duration::from_millis(300)).await;
|
|
2943
|
+
// initiate shutdown, then complete open tasks
|
|
2944
|
+
worker.initiate_shutdown();
|
|
2945
|
+
for t in tasks {
|
|
2946
|
+
worker
|
|
2947
|
+
.complete_workflow_activation(WorkflowActivationCompletion::empty(t.run_id))
|
|
2948
|
+
.await
|
|
2949
|
+
.unwrap();
|
|
2950
|
+
}
|
|
2951
|
+
worker.shutdown().await;
|
|
2952
|
+
};
|
|
2953
|
+
join!(hung_poll, ender);
|
|
2954
|
+
// We shouldn't have got more than the 10 tasks from the poller -- verifying that the concurrent
|
|
2955
|
+
// polling is not exceeding the task limit
|
|
2956
|
+
assert_eq!(popped_tasks.load(Ordering::Relaxed), 10);
|
|
2957
|
+
}
|
|
@@ -7,6 +7,7 @@ use futures::StreamExt;
|
|
|
7
7
|
use serde::Deserialize;
|
|
8
8
|
use std::{
|
|
9
9
|
fs::OpenOptions,
|
|
10
|
+
io,
|
|
10
11
|
path::{Path, PathBuf},
|
|
11
12
|
};
|
|
12
13
|
use temporal_client::ClientOptionsBuilder;
|
|
@@ -22,99 +23,6 @@ use zip::read::read_zipfile_from_stream;
|
|
|
22
23
|
use std::os::unix::fs::OpenOptionsExt;
|
|
23
24
|
use std::process::Stdio;
|
|
24
25
|
|
|
25
|
-
/// Configuration for Temporalite.
|
|
26
|
-
/// Will be removed eventually as its successor, Temporal CLI matures.
|
|
27
|
-
/// We don't care for the duplication between this struct and [TemporalDevServerConfig] and prefer that over another
|
|
28
|
-
/// abstraction since the existence of this struct is temporary.
|
|
29
|
-
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
30
|
-
pub struct TemporaliteConfig {
|
|
31
|
-
/// Required path to executable or download info.
|
|
32
|
-
pub exe: EphemeralExe,
|
|
33
|
-
/// Namespace to use.
|
|
34
|
-
#[builder(default = "\"default\".to_owned()")]
|
|
35
|
-
pub namespace: String,
|
|
36
|
-
/// IP to bind to.
|
|
37
|
-
#[builder(default = "\"127.0.0.1\".to_owned()")]
|
|
38
|
-
pub ip: String,
|
|
39
|
-
/// Port to use or obtains a free one if none given.
|
|
40
|
-
#[builder(default)]
|
|
41
|
-
pub port: Option<u16>,
|
|
42
|
-
/// Sqlite DB filename if persisting or non-persistent if none.
|
|
43
|
-
#[builder(default)]
|
|
44
|
-
pub db_filename: Option<String>,
|
|
45
|
-
/// Whether to enable the UI.
|
|
46
|
-
#[builder(default)]
|
|
47
|
-
pub ui: bool,
|
|
48
|
-
/// Log format and level
|
|
49
|
-
#[builder(default = "(\"pretty\".to_owned(), \"warn\".to_owned())")]
|
|
50
|
-
pub log: (String, String),
|
|
51
|
-
/// Additional arguments to Temporalite.
|
|
52
|
-
#[builder(default)]
|
|
53
|
-
pub extra_args: Vec<String>,
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
impl TemporaliteConfig {
|
|
57
|
-
/// Start a Temporalite server.
|
|
58
|
-
pub async fn start_server(&self) -> anyhow::Result<EphemeralServer> {
|
|
59
|
-
self.start_server_with_output(Stdio::inherit(), Stdio::inherit())
|
|
60
|
-
.await
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/// Start a Temporalite server with configurable stdout destination.
|
|
64
|
-
pub async fn start_server_with_output(
|
|
65
|
-
&self,
|
|
66
|
-
output: Stdio,
|
|
67
|
-
err_output: Stdio,
|
|
68
|
-
) -> anyhow::Result<EphemeralServer> {
|
|
69
|
-
// Get exe path
|
|
70
|
-
let exe_path = self
|
|
71
|
-
.exe
|
|
72
|
-
.get_or_download("temporalite", "temporalite", None)
|
|
73
|
-
.await?;
|
|
74
|
-
|
|
75
|
-
// Get free port if not already given
|
|
76
|
-
let port = self.port.unwrap_or_else(|| get_free_port(&self.ip));
|
|
77
|
-
|
|
78
|
-
// Build arg set
|
|
79
|
-
let mut args = vec![
|
|
80
|
-
"start".to_owned(),
|
|
81
|
-
"--port".to_owned(),
|
|
82
|
-
port.to_string(),
|
|
83
|
-
"--namespace".to_owned(),
|
|
84
|
-
self.namespace.clone(),
|
|
85
|
-
"--ip".to_owned(),
|
|
86
|
-
self.ip.clone(),
|
|
87
|
-
"--log-format".to_owned(),
|
|
88
|
-
self.log.0.clone(),
|
|
89
|
-
"--log-level".to_owned(),
|
|
90
|
-
self.log.1.clone(),
|
|
91
|
-
"--dynamic-config-value".to_owned(),
|
|
92
|
-
"frontend.enableServerVersionCheck=false".to_owned(),
|
|
93
|
-
];
|
|
94
|
-
if let Some(db_filename) = &self.db_filename {
|
|
95
|
-
args.push("--filename".to_owned());
|
|
96
|
-
args.push(db_filename.clone());
|
|
97
|
-
} else {
|
|
98
|
-
args.push("--ephemeral".to_owned());
|
|
99
|
-
}
|
|
100
|
-
if !self.ui {
|
|
101
|
-
args.push("--headless".to_owned());
|
|
102
|
-
}
|
|
103
|
-
args.extend(self.extra_args.clone());
|
|
104
|
-
|
|
105
|
-
// Start
|
|
106
|
-
EphemeralServer::start(EphemeralServerConfig {
|
|
107
|
-
exe_path,
|
|
108
|
-
port,
|
|
109
|
-
args,
|
|
110
|
-
has_test_service: false,
|
|
111
|
-
output,
|
|
112
|
-
err_output,
|
|
113
|
-
})
|
|
114
|
-
.await
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
26
|
/// Configuration for Temporal CLI dev server.
|
|
119
27
|
#[derive(Debug, Clone, derive_builder::Builder)]
|
|
120
28
|
pub struct TemporalDevServerConfig {
|
|
@@ -163,7 +71,10 @@ impl TemporalDevServerConfig {
|
|
|
163
71
|
.await?;
|
|
164
72
|
|
|
165
73
|
// Get free port if not already given
|
|
166
|
-
let port = self.port
|
|
74
|
+
let port = match self.port {
|
|
75
|
+
Some(p) => p,
|
|
76
|
+
None => get_free_port(&self.ip)?,
|
|
77
|
+
};
|
|
167
78
|
|
|
168
79
|
// Build arg set
|
|
169
80
|
let mut args = vec![
|
|
@@ -241,7 +152,10 @@ impl TestServerConfig {
|
|
|
241
152
|
.await?;
|
|
242
153
|
|
|
243
154
|
// Get free port if not already given
|
|
244
|
-
let port = self.port
|
|
155
|
+
let port = match self.port {
|
|
156
|
+
Some(p) => p,
|
|
157
|
+
None => get_free_port("0.0.0.0")?,
|
|
158
|
+
};
|
|
245
159
|
|
|
246
160
|
// Build arg set
|
|
247
161
|
let mut args = vec![port.to_string()];
|
|
@@ -307,11 +221,7 @@ impl EphemeralServer {
|
|
|
307
221
|
.build()?;
|
|
308
222
|
for _ in 0..50 {
|
|
309
223
|
sleep(Duration::from_millis(100)).await;
|
|
310
|
-
if client_options
|
|
311
|
-
.connect_no_namespace(None, None)
|
|
312
|
-
.await
|
|
313
|
-
.is_ok()
|
|
314
|
-
{
|
|
224
|
+
if client_options.connect_no_namespace(None).await.is_ok() {
|
|
315
225
|
return success;
|
|
316
226
|
}
|
|
317
227
|
}
|
|
@@ -322,7 +232,6 @@ impl EphemeralServer {
|
|
|
322
232
|
/// a kill if the child process appears completed, but such a check is not
|
|
323
233
|
/// atomic so a kill could still fail as completed if completed just before
|
|
324
234
|
/// kill.
|
|
325
|
-
#[cfg(not(target_family = "unix"))]
|
|
326
235
|
pub async fn shutdown(&mut self) -> anyhow::Result<()> {
|
|
327
236
|
// Only kill if there is a PID
|
|
328
237
|
if self.child.id().is_some() {
|
|
@@ -332,32 +241,10 @@ impl EphemeralServer {
|
|
|
332
241
|
}
|
|
333
242
|
}
|
|
334
243
|
|
|
335
|
-
///
|
|
336
|
-
///
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
#[cfg(target_family = "unix")]
|
|
340
|
-
pub async fn shutdown(&mut self) -> anyhow::Result<()> {
|
|
341
|
-
// For whatever reason, Tokio is not properly waiting on result
|
|
342
|
-
// after sending kill in some cases which is causing defunct zombie
|
|
343
|
-
// processes to remain and kill() to hang. Therefore, we are sending
|
|
344
|
-
// SIGKILL and waiting on the process ourselves using a low-level call.
|
|
345
|
-
//
|
|
346
|
-
// WARNING: This is based on empirical evidence starting a Python test
|
|
347
|
-
// run on Linux with Python 3.7 (does not happen on Python 3.10 nor does
|
|
348
|
-
// it happen on Temporalite nor does it happen in Rust integration
|
|
349
|
-
// tests). Don't alter without running that scenario. EX: SIGINT works but not SIGKILL
|
|
350
|
-
if let Some(pid) = self.child.id() {
|
|
351
|
-
let nix_pid = nix::unistd::Pid::from_raw(pid as i32);
|
|
352
|
-
Ok(spawn_blocking(move || {
|
|
353
|
-
nix::sys::signal::kill(nix_pid, nix::sys::signal::Signal::SIGINT)?;
|
|
354
|
-
nix::sys::wait::waitpid(Some(nix_pid), None)
|
|
355
|
-
})
|
|
356
|
-
.await?
|
|
357
|
-
.map(|_| ())?)
|
|
358
|
-
} else {
|
|
359
|
-
Ok(())
|
|
360
|
-
}
|
|
244
|
+
/// Get the process ID of the child. This will be None if the process is
|
|
245
|
+
/// considered to be complete.
|
|
246
|
+
pub fn child_process_id(&self) -> Option<u32> {
|
|
247
|
+
self.child.id()
|
|
361
248
|
}
|
|
362
249
|
}
|
|
363
250
|
|
|
@@ -492,14 +379,53 @@ impl EphemeralExe {
|
|
|
492
379
|
}
|
|
493
380
|
}
|
|
494
381
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
382
|
+
/// Returns a TCP port that is available to listen on for the given local host.
|
|
383
|
+
///
|
|
384
|
+
/// This works by binding a new TCP socket on port 0, which requests the OS to
|
|
385
|
+
/// allocate a free port. There is no strict guarantee that the port will remain
|
|
386
|
+
/// available after this function returns, but it should be safe to assume that
|
|
387
|
+
/// a given port will not be allocated again to any process on this machine
|
|
388
|
+
/// within a few seconds.
|
|
389
|
+
///
|
|
390
|
+
/// On Unix-based systems, binding to the port returned by this function
|
|
391
|
+
/// requires setting the `SO_REUSEADDR` socket option (Rust already does that by
|
|
392
|
+
/// default, but other languages may not); otherwise, the OS may fail with a
|
|
393
|
+
/// message such as "address already in use". Windows default behavior is
|
|
394
|
+
/// already appropriate in this regard; on that platform, `SO_REUSEADDR` has a
|
|
395
|
+
/// different meaning and should not be set (setting it may have unpredictable
|
|
396
|
+
/// consequences).
|
|
397
|
+
fn get_free_port(bind_ip: &str) -> io::Result<u16> {
|
|
398
|
+
let listen = std::net::TcpListener::bind((bind_ip, 0))?;
|
|
399
|
+
let addr = listen.local_addr()?;
|
|
400
|
+
|
|
401
|
+
// On Linux and some BSD variants, ephemeral ports are randomized, and may
|
|
402
|
+
// consequently repeat within a short time frame after the listenning end
|
|
403
|
+
// has been closed. To avoid this, we make a connection to the port, then
|
|
404
|
+
// close that connection from the server's side (this is very important),
|
|
405
|
+
// which puts the connection in TIME_WAIT state for some time (by default,
|
|
406
|
+
// 60s on Linux). While it remains in that state, the OS will not reallocate
|
|
407
|
+
// that port number for bind(:0) syscalls, yet we are not prevented from
|
|
408
|
+
// explicitly binding to it (thanks to SO_REUSEADDR).
|
|
409
|
+
//
|
|
410
|
+
// On macOS and Windows, the above technique is not necessary, as the OS
|
|
411
|
+
// allocates ephemeral ports sequentially, meaning a port number will only
|
|
412
|
+
// be reused after the entire range has been exhausted. Quite the opposite,
|
|
413
|
+
// given that these OSes use a significantly smaller range for ephemeral
|
|
414
|
+
// ports, making an extra connection just to reserve a port might actually
|
|
415
|
+
// be harmful (by hastening ephemeral port exhaustion).
|
|
416
|
+
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
|
|
417
|
+
{
|
|
418
|
+
// Establish a connection to the bind_ip:port
|
|
419
|
+
let _stream = std::net::TcpStream::connect(addr)?;
|
|
420
|
+
|
|
421
|
+
// Accept the connection from the listening side
|
|
422
|
+
let (socket, _addr) = listen.accept()?;
|
|
423
|
+
|
|
424
|
+
// Explicitly drop the socket to close the connection from the listening side first
|
|
425
|
+
std::mem::drop(socket);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
Ok(addr.port())
|
|
503
429
|
}
|
|
504
430
|
|
|
505
431
|
/// Returns false if we successfully waited for another download to complete, or
|
|
@@ -625,7 +551,7 @@ async fn download_and_extract(
|
|
|
625
551
|
// that requires Seek.
|
|
626
552
|
if let Some(mut file) = read_zipfile_from_stream(&mut reader)? {
|
|
627
553
|
// If this is the file we're expecting, extract it
|
|
628
|
-
if file.enclosed_name() == Some(&file_to_extract) {
|
|
554
|
+
if file.enclosed_name().as_ref() == Some(&file_to_extract) {
|
|
629
555
|
std::io::copy(&mut file, &mut dest)?;
|
|
630
556
|
return Ok(());
|
|
631
557
|
}
|
|
@@ -637,3 +563,50 @@ async fn download_and_extract(
|
|
|
637
563
|
})
|
|
638
564
|
.await?
|
|
639
565
|
}
|
|
566
|
+
|
|
567
|
+
#[cfg(test)]
|
|
568
|
+
mod tests {
|
|
569
|
+
use super::get_free_port;
|
|
570
|
+
use std::collections::HashSet;
|
|
571
|
+
use std::net::{TcpListener, TcpStream};
|
|
572
|
+
|
|
573
|
+
#[test]
|
|
574
|
+
fn get_free_port_no_double() {
|
|
575
|
+
let host = "127.0.0.1";
|
|
576
|
+
let mut port_set = HashSet::new();
|
|
577
|
+
|
|
578
|
+
for _ in 0..2000 {
|
|
579
|
+
let port = get_free_port(host).unwrap();
|
|
580
|
+
assert!(
|
|
581
|
+
!port_set.contains(&port),
|
|
582
|
+
"Port {port} has been assigned more than once"
|
|
583
|
+
);
|
|
584
|
+
|
|
585
|
+
// Add port to the set
|
|
586
|
+
port_set.insert(port);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
#[test]
|
|
591
|
+
fn get_free_port_can_bind_immediately() {
|
|
592
|
+
let host = "127.0.0.1";
|
|
593
|
+
|
|
594
|
+
for _ in 0..500 {
|
|
595
|
+
let port = get_free_port(host).unwrap();
|
|
596
|
+
try_listen_and_dial_on(host, port).expect("Failed to bind to port");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
fn try_listen_and_dial_on(host: &str, port: u16) -> std::io::Result<()> {
|
|
601
|
+
let listener = TcpListener::bind((host, port))?;
|
|
602
|
+
let _stream = TcpStream::connect((host, port))?;
|
|
603
|
+
|
|
604
|
+
// Accept the connection from the listening side
|
|
605
|
+
let (socket, _addr) = listener.accept()?;
|
|
606
|
+
|
|
607
|
+
// Explicitly drop the socket to close the connection from the listening side first
|
|
608
|
+
std::mem::drop(socket);
|
|
609
|
+
|
|
610
|
+
Ok(())
|
|
611
|
+
}
|
|
612
|
+
}
|
|
@@ -43,7 +43,7 @@ pub(crate) enum InternalFlags {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
impl InternalFlags {
|
|
46
|
-
pub fn new(server_capabilities: &get_system_info_response::Capabilities) -> Self {
|
|
46
|
+
pub(crate) fn new(server_capabilities: &get_system_info_response::Capabilities) -> Self {
|
|
47
47
|
match server_capabilities.sdk_metadata {
|
|
48
48
|
true => Self::Enabled {
|
|
49
49
|
core: Default::default(),
|
|
@@ -55,7 +55,7 @@ impl InternalFlags {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
pub fn add_from_complete(&mut self, e: &WorkflowTaskCompletedEventAttributes) {
|
|
58
|
+
pub(crate) fn add_from_complete(&mut self, e: &WorkflowTaskCompletedEventAttributes) {
|
|
59
59
|
if let Self::Enabled { core, lang, .. } = self {
|
|
60
60
|
if let Some(metadata) = e.sdk_metadata.as_ref() {
|
|
61
61
|
core.extend(
|
|
@@ -69,7 +69,7 @@ impl InternalFlags {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
pub fn add_lang_used(&mut self, flags: impl IntoIterator<Item = u32>) {
|
|
72
|
+
pub(crate) fn add_lang_used(&mut self, flags: impl IntoIterator<Item = u32>) {
|
|
73
73
|
if let Self::Enabled {
|
|
74
74
|
lang_since_last_complete,
|
|
75
75
|
..
|
|
@@ -82,7 +82,7 @@ impl InternalFlags {
|
|
|
82
82
|
/// Returns true if this flag may currently be used. If `should_record` is true, always returns
|
|
83
83
|
/// true and records the flag as being used, for taking later via
|
|
84
84
|
/// [Self::gather_for_wft_complete].
|
|
85
|
-
pub fn try_use(&mut self, core_patch: CoreInternalFlags, should_record: bool) -> bool {
|
|
85
|
+
pub(crate) fn try_use(&mut self, core_patch: CoreInternalFlags, should_record: bool) -> bool {
|
|
86
86
|
match self {
|
|
87
87
|
Self::Enabled {
|
|
88
88
|
core,
|
|
@@ -104,7 +104,7 @@ impl InternalFlags {
|
|
|
104
104
|
|
|
105
105
|
/// Writes all known core flags to the set which should be recorded in the current WFT if not
|
|
106
106
|
/// already known. Must only be called if not replaying.
|
|
107
|
-
pub fn write_all_known(&mut self) {
|
|
107
|
+
pub(crate) fn write_all_known(&mut self) {
|
|
108
108
|
if let Self::Enabled {
|
|
109
109
|
core_since_last_complete,
|
|
110
110
|
..
|
|
@@ -117,7 +117,7 @@ impl InternalFlags {
|
|
|
117
117
|
/// Wipes the recorded flags used during the current WFT and returns a partially filled
|
|
118
118
|
/// sdk metadata message that can be combined with any existing data before sending the WFT
|
|
119
119
|
/// complete
|
|
120
|
-
pub fn gather_for_wft_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
120
|
+
pub(crate) fn gather_for_wft_complete(&mut self) -> WorkflowTaskCompletedMetadata {
|
|
121
121
|
match self {
|
|
122
122
|
Self::Enabled {
|
|
123
123
|
core_since_last_complete,
|
|
@@ -148,7 +148,7 @@ impl InternalFlags {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
pub fn all_lang(&self) -> impl Iterator<Item = u32> + '_ {
|
|
151
|
+
pub(crate) fn all_lang(&self) -> impl Iterator<Item = u32> + '_ {
|
|
152
152
|
match self {
|
|
153
153
|
Self::Enabled { lang, .. } => Either::Left(lang.iter().copied()),
|
|
154
154
|
Self::Disabled => Either::Right(iter::empty()),
|
|
@@ -165,7 +165,7 @@ impl CoreInternalFlags {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
pub fn all_except_too_high() -> impl Iterator<Item = CoreInternalFlags> {
|
|
168
|
+
pub(crate) fn all_except_too_high() -> impl Iterator<Item = CoreInternalFlags> {
|
|
169
169
|
enum_iterator::all::<CoreInternalFlags>()
|
|
170
170
|
.filter(|f| !matches!(f, CoreInternalFlags::TooHigh))
|
|
171
171
|
}
|
package/sdk-core/core/src/lib.rs
CHANGED
|
@@ -38,9 +38,10 @@ pub use temporal_sdk_core_api as api;
|
|
|
38
38
|
pub use temporal_sdk_core_protos as protos;
|
|
39
39
|
pub use temporal_sdk_core_protos::TaskToken;
|
|
40
40
|
pub use url::Url;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
pub use worker::{
|
|
42
|
+
FixedSizeSlotSupplier, RealSysInfo, ResourceBasedSlots, ResourceBasedTuner,
|
|
43
|
+
ResourceSlotOptions, TunerBuilder, TunerHolder, Worker, WorkerConfig, WorkerConfigBuilder,
|
|
44
|
+
};
|
|
44
45
|
|
|
45
46
|
use crate::{
|
|
46
47
|
replay::{HistoryForReplay, ReplayWorkerInput},
|
|
@@ -79,14 +80,7 @@ pub fn init_worker<CT>(
|
|
|
79
80
|
where
|
|
80
81
|
CT: Into<sealed::AnyClient>,
|
|
81
82
|
{
|
|
82
|
-
let client =
|
|
83
|
-
let ll = client.into().into_inner();
|
|
84
|
-
let mut client = Client::new(*ll, worker_config.namespace.clone());
|
|
85
|
-
if let Some(ref id_override) = worker_config.client_identity_override {
|
|
86
|
-
client.options_mut().identity = id_override.clone();
|
|
87
|
-
}
|
|
88
|
-
RetryClient::new(client, RetryConfig::default())
|
|
89
|
-
};
|
|
83
|
+
let client = init_worker_client(&worker_config, *client.into().into_inner());
|
|
90
84
|
if client.namespace() != worker_config.namespace {
|
|
91
85
|
panic!("Passed in client is not bound to the same namespace as the worker");
|
|
92
86
|
}
|
|
@@ -125,6 +119,17 @@ where
|
|
|
125
119
|
rwi.into_core_worker()
|
|
126
120
|
}
|
|
127
121
|
|
|
122
|
+
pub(crate) fn init_worker_client(
|
|
123
|
+
config: &WorkerConfig,
|
|
124
|
+
client: ConfiguredClient<TemporalServiceClientWithMetrics>,
|
|
125
|
+
) -> RetryClient<Client> {
|
|
126
|
+
let mut client = Client::new(client, config.namespace.clone());
|
|
127
|
+
if let Some(ref id_override) = config.client_identity_override {
|
|
128
|
+
client.options_mut().identity.clone_from(id_override);
|
|
129
|
+
}
|
|
130
|
+
RetryClient::new(client, RetryConfig::default())
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
/// Creates a unique sticky queue name for a worker, iff the config allows for 1 or more cached
|
|
129
134
|
/// workflows.
|
|
130
135
|
pub(crate) fn sticky_q_name_for_worker(
|
|
@@ -17,15 +17,16 @@ use temporal_sdk_core_protos::temporal::api::workflowservice::v1::{
|
|
|
17
17
|
use futures::Future;
|
|
18
18
|
#[cfg(test)]
|
|
19
19
|
pub(crate) use poll_buffer::MockPermittedPollBuffer;
|
|
20
|
+
use temporal_sdk_core_api::worker::{ActivitySlotKind, WorkflowSlotKind};
|
|
20
21
|
|
|
21
|
-
pub type Result<T, E = tonic::Status> = std::result::Result<T, E>;
|
|
22
|
+
pub(crate) type Result<T, E = tonic::Status> = std::result::Result<T, E>;
|
|
22
23
|
|
|
23
24
|
/// A trait for things that poll the server. Hides complexity of concurrent polling or polling
|
|
24
25
|
/// on sticky/nonsticky queues simultaneously.
|
|
25
26
|
#[cfg_attr(test, mockall::automock)]
|
|
26
27
|
#[cfg_attr(test, allow(unused))]
|
|
27
28
|
#[async_trait::async_trait]
|
|
28
|
-
pub trait Poller<PollResult>
|
|
29
|
+
pub(crate) trait Poller<PollResult>
|
|
29
30
|
where
|
|
30
31
|
PollResult: Send + Sync + 'static,
|
|
31
32
|
{
|
|
@@ -36,9 +37,14 @@ where
|
|
|
36
37
|
async fn shutdown_box(self: Box<Self>);
|
|
37
38
|
}
|
|
38
39
|
pub(crate) type BoxedPoller<T> = Box<dyn Poller<T> + Send + Sync + 'static>;
|
|
39
|
-
pub(crate) type BoxedWFPoller = BoxedPoller<(
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
pub(crate) type BoxedWFPoller = BoxedPoller<(
|
|
41
|
+
PollWorkflowTaskQueueResponse,
|
|
42
|
+
OwnedMeteredSemPermit<WorkflowSlotKind>,
|
|
43
|
+
)>;
|
|
44
|
+
pub(crate) type BoxedActPoller = BoxedPoller<(
|
|
45
|
+
PollActivityTaskQueueResponse,
|
|
46
|
+
OwnedMeteredSemPermit<ActivitySlotKind>,
|
|
47
|
+
)>;
|
|
42
48
|
|
|
43
49
|
#[async_trait::async_trait]
|
|
44
50
|
impl<T> Poller<T> for Box<dyn Poller<T> + Send + Sync>
|