chalk-remote-call-python 1.8.0__tar.gz → 1.8.2__tar.gz
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.
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/PKG-INFO +1 -1
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/Cargo.lock +19 -19
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/Cargo.toml +3 -3
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/async_service.rs +15 -2
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/coalesce.rs +60 -3
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/lib.rs +29 -16
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/metrics.rs +33 -20
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/self_consumer.rs +72 -23
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/server.rs +25 -9
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/service.rs +37 -2
- chalk_remote_call_python-1.8.2/chalk_remote_call/_version.py +1 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/PKG-INFO +1 -1
- chalk_remote_call_python-1.8.0/chalk_remote_call/_version.py +0 -1
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/MANIFEST.in +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/README.md +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/Cargo.toml +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/Cargo.toml +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.auth.v1.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.common.v1.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.tonic.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.utils.v1.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/descriptor.bin +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/lib.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/chalk-remote-call-server/src/python_bridge.rs +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/rust-toolchain.toml +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/__main__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/auth/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/auth/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/common/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/common/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/runtime/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/runtime/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_native.pyi +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/arrow_utils.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/cli.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/handler_loader.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/input_transform.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/server.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/servicer.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/tracing.py +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/SOURCES.txt +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/dependency_links.txt +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/entry_points.txt +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/requires.txt +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call_python.egg-info/top_level.txt +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/pyproject.toml +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/setup.cfg +0 -0
- {chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/setup.py +0 -0
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/Cargo.lock
RENAMED
|
@@ -483,8 +483,8 @@ dependencies = [
|
|
|
483
483
|
|
|
484
484
|
[[package]]
|
|
485
485
|
name = "chalk-core"
|
|
486
|
-
version = "0.
|
|
487
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
486
|
+
version = "0.0.0"
|
|
487
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
488
488
|
dependencies = [
|
|
489
489
|
"anyhow",
|
|
490
490
|
"envconfig",
|
|
@@ -498,8 +498,8 @@ dependencies = [
|
|
|
498
498
|
|
|
499
499
|
[[package]]
|
|
500
500
|
name = "chalk-protos"
|
|
501
|
-
version = "0.
|
|
502
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
501
|
+
version = "0.0.0"
|
|
502
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
503
503
|
dependencies = [
|
|
504
504
|
"prost 0.11.9",
|
|
505
505
|
"prost-build",
|
|
@@ -510,8 +510,8 @@ dependencies = [
|
|
|
510
510
|
|
|
511
511
|
[[package]]
|
|
512
512
|
name = "chalk-queue"
|
|
513
|
-
version = "0.
|
|
514
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
513
|
+
version = "0.0.0"
|
|
514
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
515
515
|
dependencies = [
|
|
516
516
|
"base64 0.22.1",
|
|
517
517
|
"redis",
|
|
@@ -559,8 +559,8 @@ dependencies = [
|
|
|
559
559
|
|
|
560
560
|
[[package]]
|
|
561
561
|
name = "chalk_metric_definitions"
|
|
562
|
-
version = "0.
|
|
563
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
562
|
+
version = "0.0.0"
|
|
563
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
564
564
|
dependencies = [
|
|
565
565
|
"chalk-protos",
|
|
566
566
|
"metrics-generator",
|
|
@@ -569,8 +569,8 @@ dependencies = [
|
|
|
569
569
|
|
|
570
570
|
[[package]]
|
|
571
571
|
name = "chalk_metrics"
|
|
572
|
-
version = "0.
|
|
573
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
572
|
+
version = "0.0.0"
|
|
573
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
574
574
|
dependencies = [
|
|
575
575
|
"async-trait",
|
|
576
576
|
"chalk-core",
|
|
@@ -603,8 +603,8 @@ dependencies = [
|
|
|
603
603
|
|
|
604
604
|
[[package]]
|
|
605
605
|
name = "chalk_statsd"
|
|
606
|
-
version = "0.
|
|
607
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
606
|
+
version = "0.0.0"
|
|
607
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
608
608
|
dependencies = [
|
|
609
609
|
"chalk-core",
|
|
610
610
|
"chrono",
|
|
@@ -874,7 +874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
874
874
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
875
875
|
dependencies = [
|
|
876
876
|
"libc",
|
|
877
|
-
"windows-sys 0.
|
|
877
|
+
"windows-sys 0.61.2",
|
|
878
878
|
]
|
|
879
879
|
|
|
880
880
|
[[package]]
|
|
@@ -1472,7 +1472,7 @@ dependencies = [
|
|
|
1472
1472
|
"libc",
|
|
1473
1473
|
"percent-encoding",
|
|
1474
1474
|
"pin-project-lite",
|
|
1475
|
-
"socket2 0.
|
|
1475
|
+
"socket2 0.6.3",
|
|
1476
1476
|
"tokio",
|
|
1477
1477
|
"tower-service",
|
|
1478
1478
|
"tracing",
|
|
@@ -1867,7 +1867,7 @@ dependencies = [
|
|
|
1867
1867
|
[[package]]
|
|
1868
1868
|
name = "metrics-generator"
|
|
1869
1869
|
version = "0.1.0"
|
|
1870
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
1870
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=ae8e792f746f77253f682ee0c56b246cfdd88f51#ae8e792f746f77253f682ee0c56b246cfdd88f51"
|
|
1871
1871
|
dependencies = [
|
|
1872
1872
|
"codegen",
|
|
1873
1873
|
"serde",
|
|
@@ -2100,7 +2100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
2100
2100
|
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
|
2101
2101
|
dependencies = [
|
|
2102
2102
|
"libc",
|
|
2103
|
-
"windows-sys 0.
|
|
2103
|
+
"windows-sys 0.61.2",
|
|
2104
2104
|
]
|
|
2105
2105
|
|
|
2106
2106
|
[[package]]
|
|
@@ -2761,7 +2761,7 @@ dependencies = [
|
|
|
2761
2761
|
"errno",
|
|
2762
2762
|
"libc",
|
|
2763
2763
|
"linux-raw-sys 0.12.1",
|
|
2764
|
-
"windows-sys 0.
|
|
2764
|
+
"windows-sys 0.61.2",
|
|
2765
2765
|
]
|
|
2766
2766
|
|
|
2767
2767
|
[[package]]
|
|
@@ -3128,10 +3128,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
3128
3128
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
|
3129
3129
|
dependencies = [
|
|
3130
3130
|
"fastrand",
|
|
3131
|
-
"getrandom 0.
|
|
3131
|
+
"getrandom 0.4.2",
|
|
3132
3132
|
"once_cell",
|
|
3133
3133
|
"rustix 1.1.4",
|
|
3134
|
-
"windows-sys 0.
|
|
3134
|
+
"windows-sys 0.61.2",
|
|
3135
3135
|
]
|
|
3136
3136
|
|
|
3137
3137
|
[[package]]
|
|
@@ -36,6 +36,6 @@ futures-util = "0.3"
|
|
|
36
36
|
# `[patch.crates-io]` here it builds against vanilla crates.io redis (it only
|
|
37
37
|
# uses standard APIs). Same rev across all three so cargo reuses one checkout.
|
|
38
38
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
39
|
-
chalk-queue = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "
|
|
40
|
-
chalk_metrics = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "
|
|
41
|
-
chalk_statsd = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "
|
|
39
|
+
chalk-queue = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "ae8e792f746f77253f682ee0c56b246cfdd88f51" }
|
|
40
|
+
chalk_metrics = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "ae8e792f746f77253f682ee0c56b246cfdd88f51" }
|
|
41
|
+
chalk_statsd = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "ae8e792f746f77253f682ee0c56b246cfdd88f51" }
|
|
@@ -10,7 +10,7 @@ use chalk_remote_call_proto::chalk::runtime::v1::{
|
|
|
10
10
|
PollRemoteCallResponse, PurgeQueueRequest, PurgeQueueResponse, RemoteCallStatus,
|
|
11
11
|
};
|
|
12
12
|
use tonic::{Request, Response, Status};
|
|
13
|
-
use tracing::{debug, error, info, instrument};
|
|
13
|
+
use tracing::{debug, error, info, instrument, warn};
|
|
14
14
|
|
|
15
15
|
use crate::python_bridge::{ChunkBuffer, PythonHandler};
|
|
16
16
|
use crate::service::extract_metadata;
|
|
@@ -87,10 +87,15 @@ pub struct AsyncRemoteCallServiceImpl {
|
|
|
87
87
|
/// the per-call dispatch does not satisfy, so async enqueue is refused
|
|
88
88
|
/// rather than silently calling the handler with the wrong shape.
|
|
89
89
|
batching_enabled: bool,
|
|
90
|
+
is_remote_function: bool,
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
impl AsyncRemoteCallServiceImpl {
|
|
93
|
-
pub fn new(
|
|
94
|
+
pub fn new(
|
|
95
|
+
python_handler: Arc<PythonHandler>,
|
|
96
|
+
batching_enabled: bool,
|
|
97
|
+
is_remote_function: bool,
|
|
98
|
+
) -> Self {
|
|
94
99
|
let registry: Registry = Arc::new(Mutex::new(HashMap::new()));
|
|
95
100
|
// Runs inside the server's tokio runtime (the service is constructed
|
|
96
101
|
// within `run_server`); reclaims orphaned terminal entries.
|
|
@@ -100,6 +105,7 @@ impl AsyncRemoteCallServiceImpl {
|
|
|
100
105
|
registry,
|
|
101
106
|
next_id: AtomicU64::new(1),
|
|
102
107
|
batching_enabled,
|
|
108
|
+
is_remote_function,
|
|
103
109
|
}
|
|
104
110
|
}
|
|
105
111
|
}
|
|
@@ -125,6 +131,13 @@ impl AsyncRemoteCallService for AsyncRemoteCallServiceImpl {
|
|
|
125
131
|
let req = request.into_inner();
|
|
126
132
|
let function_name = req.name;
|
|
127
133
|
|
|
134
|
+
if self.is_remote_function {
|
|
135
|
+
warn!(
|
|
136
|
+
function_name = %function_name,
|
|
137
|
+
"this enqueue is not fronted by the fnq server (CHALK_REMOTE_FUNCTION is set to true)"
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
// Only inline feather bytes are supported today; the object-store
|
|
129
142
|
// variant is reserved for large payloads and not wired up here.
|
|
130
143
|
let ipc_bytes = match req.args.and_then(|a| a.args) {
|
|
@@ -13,6 +13,8 @@ use tokio::task::JoinHandle;
|
|
|
13
13
|
use tonic::Status;
|
|
14
14
|
use tracing::error;
|
|
15
15
|
|
|
16
|
+
#[cfg(target_os = "linux")]
|
|
17
|
+
use chalk_metrics::PublishingMetricsPipeline;
|
|
16
18
|
use chalk_remote_call_proto::chalk::runtime::v1::CallFunctionResponse;
|
|
17
19
|
|
|
18
20
|
use crate::python_bridge::{CallerInput, PythonHandler};
|
|
@@ -35,10 +37,17 @@ pub struct CoalescingQueue {
|
|
|
35
37
|
max_size: usize,
|
|
36
38
|
max_duration: Duration,
|
|
37
39
|
state: Mutex<QueueState>,
|
|
40
|
+
#[cfg(target_os = "linux")]
|
|
41
|
+
pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
impl CoalescingQueue {
|
|
41
|
-
pub fn new(
|
|
45
|
+
pub fn new(
|
|
46
|
+
handler: Arc<PythonHandler>,
|
|
47
|
+
max_size: usize,
|
|
48
|
+
max_duration_ms: u64,
|
|
49
|
+
#[cfg(target_os = "linux")] pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
50
|
+
) -> Arc<Self> {
|
|
42
51
|
Arc::new(Self {
|
|
43
52
|
handler,
|
|
44
53
|
max_size,
|
|
@@ -47,6 +56,8 @@ impl CoalescingQueue {
|
|
|
47
56
|
items: Vec::new(),
|
|
48
57
|
flush_task: None,
|
|
49
58
|
}),
|
|
59
|
+
#[cfg(target_os = "linux")]
|
|
60
|
+
pipeline,
|
|
50
61
|
})
|
|
51
62
|
}
|
|
52
63
|
|
|
@@ -90,17 +101,33 @@ impl CoalescingQueue {
|
|
|
90
101
|
// Dispatch off the queue's critical section — don't block further
|
|
91
102
|
// submissions while Python runs.
|
|
92
103
|
let handler = Arc::clone(&self.handler);
|
|
104
|
+
#[cfg(target_os = "linux")]
|
|
105
|
+
let pipeline = self.pipeline.clone();
|
|
93
106
|
tokio::spawn(async move {
|
|
94
|
-
Self::dispatch(
|
|
107
|
+
Self::dispatch(
|
|
108
|
+
handler,
|
|
109
|
+
items,
|
|
110
|
+
#[cfg(target_os = "linux")]
|
|
111
|
+
pipeline,
|
|
112
|
+
)
|
|
113
|
+
.await;
|
|
95
114
|
});
|
|
96
115
|
}
|
|
97
116
|
|
|
98
|
-
async fn dispatch(
|
|
117
|
+
async fn dispatch(
|
|
118
|
+
handler: Arc<PythonHandler>,
|
|
119
|
+
items: Vec<BufferedCall>,
|
|
120
|
+
#[cfg(target_os = "linux")] pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
121
|
+
) {
|
|
99
122
|
// Split each BufferedCall into its input (for the bridge) and its
|
|
100
123
|
// response channel (for routing the reply back).
|
|
101
124
|
let n = items.len();
|
|
102
125
|
let mut callers: Vec<CallerInput> = Vec::with_capacity(n);
|
|
103
126
|
let mut response_txs = Vec::with_capacity(n);
|
|
127
|
+
#[cfg(target_os = "linux")]
|
|
128
|
+
let function_name = items[0].input.function_name.clone();
|
|
129
|
+
#[cfg(target_os = "linux")]
|
|
130
|
+
let started = std::time::Instant::now();
|
|
104
131
|
for item in items {
|
|
105
132
|
callers.push(item.input);
|
|
106
133
|
response_txs.push(item.response_tx);
|
|
@@ -116,11 +143,31 @@ impl CoalescingQueue {
|
|
|
116
143
|
n
|
|
117
144
|
);
|
|
118
145
|
error!("{}", msg);
|
|
146
|
+
#[cfg(target_os = "linux")]
|
|
147
|
+
if let Some(p) = &pipeline {
|
|
148
|
+
crate::metrics::record_completed_call(
|
|
149
|
+
p,
|
|
150
|
+
&function_name,
|
|
151
|
+
/* success = */ false,
|
|
152
|
+
started.elapsed(),
|
|
153
|
+
chalk_metrics::metrics::tags::Mode::Sync,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
119
156
|
for tx in &response_txs {
|
|
120
157
|
let _ = tx.send(Err(Status::unknown(msg.clone()))).await;
|
|
121
158
|
}
|
|
122
159
|
return;
|
|
123
160
|
}
|
|
161
|
+
#[cfg(target_os = "linux")]
|
|
162
|
+
if let Some(p) = &pipeline {
|
|
163
|
+
crate::metrics::record_completed_call(
|
|
164
|
+
p,
|
|
165
|
+
&function_name,
|
|
166
|
+
/* success = */ true,
|
|
167
|
+
started.elapsed(),
|
|
168
|
+
chalk_metrics::metrics::tags::Mode::Sync,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
124
171
|
for (tx, chunk) in response_txs.into_iter().zip(per_caller_bytes) {
|
|
125
172
|
let msg = CallFunctionResponse {
|
|
126
173
|
feather_stream: chunk.into(),
|
|
@@ -132,6 +179,16 @@ impl CoalescingQueue {
|
|
|
132
179
|
error!("Coalesced handler error: {}", e);
|
|
133
180
|
// IPC decode errors are already caught by the service's
|
|
134
181
|
// pre-validation; anything reaching here is a handler error.
|
|
182
|
+
#[cfg(target_os = "linux")]
|
|
183
|
+
if let Some(p) = &pipeline {
|
|
184
|
+
crate::metrics::record_completed_call(
|
|
185
|
+
p,
|
|
186
|
+
&function_name,
|
|
187
|
+
/* success = */ false,
|
|
188
|
+
started.elapsed(),
|
|
189
|
+
chalk_metrics::metrics::tags::Mode::Sync,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
135
192
|
let status =
|
|
136
193
|
Status::unknown(format!("Exception raised during handler execution: {e}"));
|
|
137
194
|
for tx in response_txs {
|
|
@@ -53,16 +53,6 @@ fn start_server(
|
|
|
53
53
|
|
|
54
54
|
let python_handler = Arc::new(PythonHandler::new(handler, process_fn, arg_names));
|
|
55
55
|
|
|
56
|
-
let coalescing_queue = if max_batching_size > 0 {
|
|
57
|
-
Some(CoalescingQueue::new(
|
|
58
|
-
Arc::clone(&python_handler),
|
|
59
|
-
max_batching_size,
|
|
60
|
-
max_buffer_duration_ms,
|
|
61
|
-
))
|
|
62
|
-
} else {
|
|
63
|
-
None
|
|
64
|
-
};
|
|
65
|
-
|
|
66
56
|
// Release the GIL while the Rust server runs
|
|
67
57
|
py.detach(|| {
|
|
68
58
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
@@ -75,12 +65,35 @@ fn start_server(
|
|
|
75
65
|
))
|
|
76
66
|
})?;
|
|
77
67
|
|
|
78
|
-
rt.block_on(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
rt.block_on(async {
|
|
69
|
+
// Linux-only: the self-consumer + its metrics pipeline depend on
|
|
70
|
+
// chalk-queue / chalk_metrics, since these don't compile on macos
|
|
71
|
+
// and windows. Built inside the runtime since it needs to `.await`.
|
|
72
|
+
#[cfg(target_os = "linux")]
|
|
73
|
+
let pipeline = crate::metrics::init_pipeline().await;
|
|
74
|
+
|
|
75
|
+
let coalescing_queue = if max_batching_size > 0 {
|
|
76
|
+
Some(CoalescingQueue::new(
|
|
77
|
+
Arc::clone(&python_handler),
|
|
78
|
+
max_batching_size,
|
|
79
|
+
max_buffer_duration_ms,
|
|
80
|
+
#[cfg(target_os = "linux")]
|
|
81
|
+
pipeline.clone(),
|
|
82
|
+
))
|
|
83
|
+
} else {
|
|
84
|
+
None
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
server::run_server(
|
|
88
|
+
host,
|
|
89
|
+
port,
|
|
90
|
+
python_handler,
|
|
91
|
+
coalescing_queue,
|
|
92
|
+
#[cfg(target_os = "linux")]
|
|
93
|
+
pipeline,
|
|
94
|
+
)
|
|
95
|
+
.await
|
|
96
|
+
})
|
|
84
97
|
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("Server error: {e}")))
|
|
85
98
|
})
|
|
86
99
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//! Metrics emission for the self-consuming shim, mirroring the catalog
|
|
2
2
|
//! consumer / fnq-server: build a `chalk_metrics` publishing pipeline at startup
|
|
3
|
-
//! and emit
|
|
3
|
+
//! and emit per-call dequeue + processing-latency metrics.
|
|
4
4
|
//!
|
|
5
5
|
//! The External Function "Function Calls Dequeued" chart reads TimescaleDB
|
|
6
6
|
//! `metrics1`, which is fed only by the chalk_metrics PubSub bus (statsd goes to
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
use std::sync::Arc;
|
|
11
11
|
use std::time::Duration;
|
|
12
12
|
|
|
13
|
-
use chalk_metrics::metrics::tags::{FunctionName, Status as MetricStatus, TagValue};
|
|
13
|
+
use chalk_metrics::metrics::tags::{FunctionName, Mode, Status as MetricStatus, TagValue};
|
|
14
14
|
use chalk_metrics::metrics::well_known_metrics::WellKnownMetricName;
|
|
15
15
|
use chalk_metrics::{
|
|
16
16
|
make_pubsub_publisher, BatchConfig, BusPublisher, MetricsPipeline, PublishingMetricsPipeline,
|
|
@@ -30,7 +30,7 @@ const BATCH_MAX_LATENCY: Duration = Duration::from_millis(100);
|
|
|
30
30
|
/// The bus publisher is what reaches the metrics store (and thus the dashboard);
|
|
31
31
|
/// statsd alone only reaches Datadog. An empty `METRICS_BUS_TOPIC` therefore
|
|
32
32
|
/// means the dashboard won't move — surfaced as a warning, not an error.
|
|
33
|
-
pub async fn init_pipeline() -> Option<Arc<
|
|
33
|
+
pub async fn init_pipeline() -> Option<Arc<PublishingMetricsPipeline>> {
|
|
34
34
|
let environment_id = std::env::var("CHALK_ENVIRONMENT_ID").unwrap_or_default();
|
|
35
35
|
|
|
36
36
|
let statsd = Arc::new(
|
|
@@ -42,12 +42,10 @@ pub async fn init_pipeline() -> Option<Arc<dyn MetricsPipeline>> {
|
|
|
42
42
|
|
|
43
43
|
let publishers: Vec<Arc<dyn BusPublisher>> = build_bus_publisher().await.into_iter().collect();
|
|
44
44
|
if publishers.is_empty() {
|
|
45
|
-
warn!(
|
|
46
|
-
"no metrics bus publisher configured; FunctionCallDequeued will not reach the dashboard"
|
|
47
|
-
);
|
|
45
|
+
warn!("no metrics bus publisher configured; function call metrics will not reach the dashboard");
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
let metrics_pipeline: Arc<
|
|
48
|
+
let metrics_pipeline: Arc<PublishingMetricsPipeline> =
|
|
51
49
|
Arc::new(PublishingMetricsPipeline::new_with_env_var_defaults(
|
|
52
50
|
environment_id,
|
|
53
51
|
String::new(),
|
|
@@ -106,24 +104,39 @@ async fn build_bus_publisher() -> Option<Arc<dyn BusPublisher>> {
|
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
/// Emit
|
|
110
|
-
///
|
|
111
|
-
///
|
|
112
|
-
///
|
|
113
|
-
|
|
107
|
+
/// Emit completed-call metrics tagged with function name and success/failure.
|
|
108
|
+
///
|
|
109
|
+
/// `FunctionCallProcessingLatency` is defined as a sketch in metrics.cue, which
|
|
110
|
+
/// is emitted through the histogram API in chalk_metrics. The shim does not
|
|
111
|
+
/// carry the scaling-group revision tag used by the legacy catalog consumer;
|
|
112
|
+
/// the dashboard filters by function name.
|
|
113
|
+
pub fn record_completed_call(
|
|
114
|
+
pipeline: &Arc<PublishingMetricsPipeline>,
|
|
115
|
+
function_name: &str,
|
|
116
|
+
success: bool,
|
|
117
|
+
elapsed: Duration,
|
|
118
|
+
mode: Mode,
|
|
119
|
+
) {
|
|
114
120
|
let status = if success {
|
|
115
121
|
MetricStatus::Success
|
|
116
122
|
} else {
|
|
117
123
|
MetricStatus::Failure
|
|
118
124
|
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
) {
|
|
125
|
+
let tags = vec![
|
|
126
|
+
TagValue::FunctionName(FunctionName(function_name.to_string())),
|
|
127
|
+
TagValue::Status(status.clone()),
|
|
128
|
+
TagValue::Mode(mode.clone()),
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
if let Err(e) = pipeline.count(WellKnownMetricName::FunctionCallDequeued, 1.0, tags.clone()) {
|
|
127
132
|
warn!(error = %e, function = %function_name, "failed to emit FunctionCallDequeued metric");
|
|
128
133
|
}
|
|
134
|
+
|
|
135
|
+
if let Err(e) = pipeline.histogram(
|
|
136
|
+
WellKnownMetricName::FunctionCallProcessingLatency,
|
|
137
|
+
elapsed.as_secs_f64() * 1000.0,
|
|
138
|
+
tags,
|
|
139
|
+
) {
|
|
140
|
+
warn!(error = %e, function = %function_name, "failed to emit FunctionCallProcessingLatency metric");
|
|
141
|
+
}
|
|
129
142
|
}
|
|
@@ -28,9 +28,10 @@
|
|
|
28
28
|
//! caller. The semaphore still admits one slot per call, so it remains the
|
|
29
29
|
//! producer of the concurrency the coalescer batches.
|
|
30
30
|
|
|
31
|
+
use std::collections::HashMap;
|
|
31
32
|
use std::panic::AssertUnwindSafe;
|
|
32
33
|
use std::sync::{Arc, Mutex};
|
|
33
|
-
use std::time::Duration;
|
|
34
|
+
use std::time::{Duration, Instant};
|
|
34
35
|
|
|
35
36
|
use chalk_queue::semaphore::renew_many;
|
|
36
37
|
use chalk_queue::stream_writer;
|
|
@@ -44,7 +45,8 @@ use tokio::sync::mpsc;
|
|
|
44
45
|
use tracing::{error, info, warn};
|
|
45
46
|
use uuid::Uuid;
|
|
46
47
|
|
|
47
|
-
use chalk_metrics::
|
|
48
|
+
use chalk_metrics::metrics::tags::Mode;
|
|
49
|
+
use chalk_metrics::PublishingMetricsPipeline;
|
|
48
50
|
|
|
49
51
|
use crate::coalesce::{BufferedCall, CoalescingQueue};
|
|
50
52
|
use crate::python_bridge::{CallerInput, ChunkBuffer, PythonHandler};
|
|
@@ -186,7 +188,7 @@ type LiveTokens = Arc<DashSet<String>>;
|
|
|
186
188
|
pub async fn run(
|
|
187
189
|
config: SelfConsumerConfig,
|
|
188
190
|
handler: Arc<PythonHandler>,
|
|
189
|
-
metrics_pipeline: Option<Arc<
|
|
191
|
+
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
190
192
|
coalescing_queue: Option<Arc<CoalescingQueue>>,
|
|
191
193
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
192
194
|
let client = Client::open(config.redis_url.clone())?;
|
|
@@ -310,7 +312,7 @@ async fn run_one_call(
|
|
|
310
312
|
lease: SemaphoreLease,
|
|
311
313
|
live_tokens: LiveTokens,
|
|
312
314
|
flush_timeout: Duration,
|
|
313
|
-
metrics_pipeline: Option<Arc<
|
|
315
|
+
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
314
316
|
) {
|
|
315
317
|
let call_id = work.call_id.clone();
|
|
316
318
|
match AssertUnwindSafe(execute_and_write(
|
|
@@ -362,7 +364,7 @@ async fn run_one_coalesced_call(
|
|
|
362
364
|
work: QueuedCall,
|
|
363
365
|
lease: SemaphoreLease,
|
|
364
366
|
live_tokens: LiveTokens,
|
|
365
|
-
metrics_pipeline: Option<Arc<
|
|
367
|
+
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
366
368
|
) {
|
|
367
369
|
let call_id = work.call_id.clone();
|
|
368
370
|
if let Err(e) = coalesced_execute_and_write(
|
|
@@ -397,13 +399,15 @@ async fn coalesced_execute_and_write(
|
|
|
397
399
|
queue: &FunctionQueue,
|
|
398
400
|
conn: &mut ConnectionManager,
|
|
399
401
|
work: QueuedCall,
|
|
400
|
-
metrics_pipeline: Option<&Arc<
|
|
402
|
+
metrics_pipeline: Option<&Arc<PublishingMetricsPipeline>>,
|
|
401
403
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
402
404
|
let call_uuid = Uuid::parse_str(&work.call_id)?;
|
|
403
405
|
let stream_key = queue.stream_key_for(call_uuid);
|
|
404
406
|
let ipc_bytes = work.call.feather_bytes()?;
|
|
405
407
|
let function_name = work.call.name.clone();
|
|
406
|
-
let metadata = work.metadata.otel_headers.clone();
|
|
408
|
+
let mut metadata = work.metadata.otel_headers.clone();
|
|
409
|
+
let processing_trace_id = ensure_traceparent(&mut metadata);
|
|
410
|
+
let started = Instant::now();
|
|
407
411
|
|
|
408
412
|
let _ = queue.update_status(call_uuid, "running").await;
|
|
409
413
|
info!(call_id = %work.call_id, function = %function_name, "running coalesced queued call");
|
|
@@ -425,11 +429,17 @@ async fn coalesced_execute_and_write(
|
|
|
425
429
|
|
|
426
430
|
let response = rx.recv().await;
|
|
427
431
|
|
|
428
|
-
// Record
|
|
429
|
-
//
|
|
432
|
+
// Record metrics once the batch has produced this caller's result, before
|
|
433
|
+
// stream writes below — parity with the streaming path.
|
|
430
434
|
let success = matches!(response, Some(Ok(_)));
|
|
431
435
|
if let Some(p) = metrics_pipeline {
|
|
432
|
-
crate::metrics::
|
|
436
|
+
crate::metrics::record_completed_call(
|
|
437
|
+
p,
|
|
438
|
+
&function_name,
|
|
439
|
+
success,
|
|
440
|
+
started.elapsed(),
|
|
441
|
+
Mode::Async,
|
|
442
|
+
);
|
|
433
443
|
}
|
|
434
444
|
|
|
435
445
|
match response {
|
|
@@ -437,7 +447,12 @@ async fn coalesced_execute_and_write(
|
|
|
437
447
|
stream_writer::write_chunk(conn, &stream_key, 1, &resp.feather_stream).await?;
|
|
438
448
|
stream_writer::write_end(conn, &stream_key, 2).await?;
|
|
439
449
|
let _ = queue
|
|
440
|
-
.complete_status(
|
|
450
|
+
.complete_status(
|
|
451
|
+
call_uuid,
|
|
452
|
+
"completed",
|
|
453
|
+
"1 chunk(s)",
|
|
454
|
+
Some(processing_trace_id),
|
|
455
|
+
)
|
|
441
456
|
.await;
|
|
442
457
|
info!(call_id = %work.call_id, "coalesced queued call completed");
|
|
443
458
|
}
|
|
@@ -454,7 +469,9 @@ async fn coalesced_execute_and_write(
|
|
|
454
469
|
)
|
|
455
470
|
.await?;
|
|
456
471
|
let summary: String = status.message().chars().take(200).collect();
|
|
457
|
-
let _ = queue
|
|
472
|
+
let _ = queue
|
|
473
|
+
.complete_status(call_uuid, "failed", &summary, Some(processing_trace_id))
|
|
474
|
+
.await;
|
|
458
475
|
error!(call_id = %work.call_id, error = %status, "coalesced queued call failed");
|
|
459
476
|
}
|
|
460
477
|
None => {
|
|
@@ -464,13 +481,31 @@ async fn coalesced_execute_and_write(
|
|
|
464
481
|
let msg = "coalesced dispatch produced no response";
|
|
465
482
|
stream_writer::write_error(conn, &stream_key, 1, "RemoteFunctionError", msg, None)
|
|
466
483
|
.await?;
|
|
467
|
-
let _ = queue
|
|
484
|
+
let _ = queue
|
|
485
|
+
.complete_status(call_uuid, "failed", msg, Some(processing_trace_id))
|
|
486
|
+
.await;
|
|
468
487
|
error!(call_id = %work.call_id, "{msg}");
|
|
469
488
|
}
|
|
470
489
|
}
|
|
471
490
|
Ok(())
|
|
472
491
|
}
|
|
473
492
|
|
|
493
|
+
// Insert trace ID into headers if none already present
|
|
494
|
+
fn ensure_traceparent(headers: &mut HashMap<String, String>) -> String {
|
|
495
|
+
if let Some(tp) = headers.get("traceparent") {
|
|
496
|
+
if let Some(trace_id) = tp.split('-').nth(1).filter(|s| s.len() == 32) {
|
|
497
|
+
return trace_id.to_string();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
let trace_id = Uuid::new_v4().simple().to_string();
|
|
501
|
+
let span_id = &Uuid::new_v4().simple().to_string()[..16];
|
|
502
|
+
headers.insert(
|
|
503
|
+
"traceparent".to_string(),
|
|
504
|
+
format!("00-{trace_id}-{span_id}-01"),
|
|
505
|
+
);
|
|
506
|
+
trace_id
|
|
507
|
+
}
|
|
508
|
+
|
|
474
509
|
/// Decode the payload, invoke the handler, and write the outcome (chunks then
|
|
475
510
|
/// `end`, or `error`) to the call's result stream, updating meta status along
|
|
476
511
|
/// the way.
|
|
@@ -480,13 +515,15 @@ async fn execute_and_write(
|
|
|
480
515
|
conn: &mut ConnectionManager,
|
|
481
516
|
work: QueuedCall,
|
|
482
517
|
flush_timeout: Duration,
|
|
483
|
-
metrics_pipeline: Option<&Arc<
|
|
518
|
+
metrics_pipeline: Option<&Arc<PublishingMetricsPipeline>>,
|
|
484
519
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
485
520
|
let call_uuid = Uuid::parse_str(&work.call_id)?;
|
|
486
521
|
let stream_key = queue.stream_key_for(call_uuid);
|
|
487
522
|
let ipc_bytes = work.call.feather_bytes()?;
|
|
488
523
|
let function_name = work.call.name.clone();
|
|
489
|
-
let metadata = work.metadata.otel_headers.clone();
|
|
524
|
+
let mut metadata = work.metadata.otel_headers.clone();
|
|
525
|
+
let processing_trace_id = ensure_traceparent(&mut metadata);
|
|
526
|
+
let started = Instant::now();
|
|
490
527
|
|
|
491
528
|
let _ = queue.update_status(call_uuid, "running").await;
|
|
492
529
|
info!(call_id = %work.call_id, function = %function_name, "running queued call");
|
|
@@ -501,7 +538,7 @@ async fn execute_and_write(
|
|
|
501
538
|
let buffer = ChunkBuffer::new().into_shared();
|
|
502
539
|
let handler_fut = handler.call_into_buffer(
|
|
503
540
|
ipc_bytes,
|
|
504
|
-
function_name,
|
|
541
|
+
function_name.clone(),
|
|
505
542
|
metadata,
|
|
506
543
|
PEER.to_string(),
|
|
507
544
|
buffer.clone(),
|
|
@@ -537,12 +574,17 @@ async fn execute_and_write(
|
|
|
537
574
|
}
|
|
538
575
|
};
|
|
539
576
|
|
|
540
|
-
// Emit
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
// the catalog consumer's per-call emission.
|
|
577
|
+
// Emit metrics as soon as execution finishes, before result-stream writes,
|
|
578
|
+
// so every executed call is recorded regardless of downstream Redis write
|
|
579
|
+
// failure. Mirrors the catalog consumer's per-call emission.
|
|
544
580
|
if let Some(p) = metrics_pipeline {
|
|
545
|
-
crate::metrics::
|
|
581
|
+
crate::metrics::record_completed_call(
|
|
582
|
+
p,
|
|
583
|
+
&function_name,
|
|
584
|
+
result.is_ok(),
|
|
585
|
+
started.elapsed(),
|
|
586
|
+
Mode::Async,
|
|
587
|
+
);
|
|
546
588
|
}
|
|
547
589
|
|
|
548
590
|
// Flush whatever the handler produced after the loop exits (on the fast path
|
|
@@ -557,7 +599,12 @@ async fn execute_and_write(
|
|
|
557
599
|
Ok(()) => {
|
|
558
600
|
stream_writer::write_end(conn, &stream_key, seq).await?;
|
|
559
601
|
let _ = queue
|
|
560
|
-
.complete_status(
|
|
602
|
+
.complete_status(
|
|
603
|
+
call_uuid,
|
|
604
|
+
"completed",
|
|
605
|
+
&format!("{flushed} chunk(s)"),
|
|
606
|
+
Some(processing_trace_id),
|
|
607
|
+
)
|
|
561
608
|
.await;
|
|
562
609
|
info!(call_id = %work.call_id, chunks = flushed, "queued call completed");
|
|
563
610
|
}
|
|
@@ -568,7 +615,9 @@ async fn execute_and_write(
|
|
|
568
615
|
stream_writer::write_error(conn, &stream_key, seq, "RemoteFunctionError", &e.0, None)
|
|
569
616
|
.await?;
|
|
570
617
|
let summary: String = e.0.chars().take(200).collect();
|
|
571
|
-
let _ = queue
|
|
618
|
+
let _ = queue
|
|
619
|
+
.complete_status(call_uuid, "failed", &summary, Some(processing_trace_id))
|
|
620
|
+
.await;
|
|
572
621
|
error!(call_id = %work.call_id, error = %e, "queued call failed");
|
|
573
622
|
}
|
|
574
623
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
use std::net::SocketAddr;
|
|
2
2
|
use std::sync::Arc;
|
|
3
3
|
|
|
4
|
+
#[cfg(target_os = "linux")]
|
|
5
|
+
use chalk_metrics::PublishingMetricsPipeline;
|
|
4
6
|
use chalk_remote_call_proto::chalk::runtime::v1::async_remote_call_service_server::AsyncRemoteCallServiceServer;
|
|
5
7
|
use chalk_remote_call_proto::chalk::runtime::v1::remote_call_service_server::RemoteCallServiceServer;
|
|
6
8
|
use chalk_remote_call_proto::chalk::runtime::v1::FILE_DESCRIPTOR_SET;
|
|
@@ -14,11 +16,14 @@ use crate::service::RemoteCallServiceImpl;
|
|
|
14
16
|
|
|
15
17
|
const MAX_MESSAGE_SIZE: usize = 32 * 1024 * 1024; // 32 MB
|
|
16
18
|
|
|
19
|
+
const ENV_REMOTE_FUNCTION: &str = "CHALK_REMOTE_FUNCTION";
|
|
20
|
+
|
|
17
21
|
pub async fn run_server(
|
|
18
22
|
host: String,
|
|
19
23
|
port: u16,
|
|
20
24
|
python_handler: Arc<PythonHandler>,
|
|
21
25
|
coalescing_queue: Option<Arc<CoalescingQueue>>,
|
|
26
|
+
#[cfg(target_os = "linux")] pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
22
27
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
23
28
|
// Parse host — ensure IPv6 addresses are bracketed for SocketAddr parsing
|
|
24
29
|
let addr_str = if host.contains(':') && !host.starts_with('[') {
|
|
@@ -57,7 +62,14 @@ pub async fn run_server(
|
|
|
57
62
|
// coalescing flag before `coalescing_queue` is moved into the streaming
|
|
58
63
|
// service below; the async path refuses enqueue when batching is on.
|
|
59
64
|
let batching_enabled = coalescing_queue.is_some();
|
|
60
|
-
|
|
65
|
+
// Checks if remote function env var is set or not
|
|
66
|
+
let is_remote_function: bool = std::env::var(ENV_REMOTE_FUNCTION)
|
|
67
|
+
.is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1");
|
|
68
|
+
let async_svc = AsyncRemoteCallServiceImpl::new(
|
|
69
|
+
python_handler.clone(),
|
|
70
|
+
batching_enabled,
|
|
71
|
+
is_remote_function,
|
|
72
|
+
);
|
|
61
73
|
|
|
62
74
|
// Self-consume the Redis fn queue when this pod was provisioned with a
|
|
63
75
|
// Redis URL (gRPC-only otherwise). The self-consumer shares the gRPC
|
|
@@ -65,20 +77,22 @@ pub async fn run_server(
|
|
|
65
77
|
// inbound gRPC calls feed the same queue so they batch together against the
|
|
66
78
|
// single batch-size/duration the user configured. When batching is off the
|
|
67
79
|
// queue is `None` and the self-consumer dispatches per-call (streaming).
|
|
68
|
-
|
|
69
|
-
// Linux-only: the self-consumer + its metrics pipeline depend on chalk-queue
|
|
70
|
-
// / chalk_metrics, since these don't compile on macos and windows.
|
|
80
|
+
|
|
71
81
|
#[cfg(target_os = "linux")]
|
|
72
82
|
if let Some(cfg) = crate::self_consumer::SelfConsumerConfig::from_env() {
|
|
73
83
|
// Build the chalk_metrics pipeline once (mirrors the fnq-server/cc
|
|
74
|
-
// main init) so the self-consumer can emit
|
|
75
|
-
let pipeline = crate::metrics::init_pipeline().await;
|
|
84
|
+
// main init) so the self-consumer can emit function-call metrics.
|
|
76
85
|
let consumer_handler = python_handler.clone();
|
|
86
|
+
let consumer_pipeline = pipeline.clone();
|
|
77
87
|
let consumer_coalescing = coalescing_queue.clone();
|
|
78
88
|
tokio::spawn(async move {
|
|
79
|
-
if let Err(e) =
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
if let Err(e) = crate::self_consumer::run(
|
|
90
|
+
cfg,
|
|
91
|
+
consumer_handler,
|
|
92
|
+
consumer_pipeline,
|
|
93
|
+
consumer_coalescing,
|
|
94
|
+
)
|
|
95
|
+
.await
|
|
82
96
|
{
|
|
83
97
|
tracing::error!(error = %e, "fnq self-consumer failed to start");
|
|
84
98
|
}
|
|
@@ -89,6 +103,8 @@ pub async fn run_server(
|
|
|
89
103
|
let svc = RemoteCallServiceImpl {
|
|
90
104
|
python_handler,
|
|
91
105
|
coalescing_queue,
|
|
106
|
+
#[cfg(target_os = "linux")]
|
|
107
|
+
metrics_pipeline: pipeline,
|
|
92
108
|
};
|
|
93
109
|
|
|
94
110
|
info!("Server starting on {}", addr);
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
use std::sync::Arc;
|
|
3
|
+
#[cfg(target_os = "linux")]
|
|
4
|
+
use std::time::Instant;
|
|
3
5
|
|
|
6
|
+
#[cfg(target_os = "linux")]
|
|
7
|
+
use chalk_metrics::metrics::tags::Mode;
|
|
8
|
+
#[cfg(target_os = "linux")]
|
|
9
|
+
use chalk_metrics::PublishingMetricsPipeline;
|
|
4
10
|
use chalk_remote_call_proto::chalk::runtime::v1::remote_call_service_server::RemoteCallService;
|
|
5
11
|
use chalk_remote_call_proto::chalk::runtime::v1::{CallFunctionRequest, CallFunctionResponse};
|
|
6
12
|
use tokio_stream::wrappers::ReceiverStream;
|
|
@@ -18,6 +24,9 @@ pub struct RemoteCallServiceImpl {
|
|
|
18
24
|
/// Optional coalescing queue. When `Some`, incoming calls are buffered and
|
|
19
25
|
/// dispatched as a single batched handler invocation.
|
|
20
26
|
pub coalescing_queue: Option<Arc<CoalescingQueue>>,
|
|
27
|
+
// Linux-gated metrics pipeline
|
|
28
|
+
#[cfg(target_os = "linux")]
|
|
29
|
+
pub metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
#[tonic::async_trait]
|
|
@@ -90,14 +99,40 @@ impl RemoteCallService for RemoteCallServiceImpl {
|
|
|
90
99
|
|
|
91
100
|
// Single-request path.
|
|
92
101
|
let handler = self.python_handler.clone();
|
|
102
|
+
#[cfg(target_os = "linux")]
|
|
103
|
+
let metrics_pipeline = self.metrics_pipeline.clone();
|
|
93
104
|
tokio::spawn(async move {
|
|
105
|
+
#[cfg(target_os = "linux")]
|
|
106
|
+
let started = Instant::now();
|
|
107
|
+
|
|
94
108
|
let error_tx = tx.clone();
|
|
95
109
|
match handler
|
|
96
|
-
.call_streaming(all_bytes, function_name, metadata, peer, tx)
|
|
110
|
+
.call_streaming(all_bytes, function_name.clone(), metadata, peer, tx)
|
|
97
111
|
.await
|
|
98
112
|
{
|
|
99
|
-
Ok(()) => {
|
|
113
|
+
Ok(()) => {
|
|
114
|
+
#[cfg(target_os = "linux")]
|
|
115
|
+
if let Some(p) = &metrics_pipeline {
|
|
116
|
+
crate::metrics::record_completed_call(
|
|
117
|
+
p,
|
|
118
|
+
&function_name,
|
|
119
|
+
/* success = */ true,
|
|
120
|
+
started.elapsed(),
|
|
121
|
+
Mode::Sync,
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
100
125
|
Err(e) => {
|
|
126
|
+
#[cfg(target_os = "linux")]
|
|
127
|
+
if let Some(p) = &metrics_pipeline {
|
|
128
|
+
crate::metrics::record_completed_call(
|
|
129
|
+
p,
|
|
130
|
+
&function_name,
|
|
131
|
+
/* success = */ false,
|
|
132
|
+
started.elapsed(),
|
|
133
|
+
Mode::Sync,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
101
136
|
if error_tx.is_closed() {
|
|
102
137
|
// The only reason blocking_send fails is a dropped
|
|
103
138
|
// receiver — the client went away mid-stream. Not a
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.8.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.8.0"
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk-remote-call-rs/Cargo.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/__init__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/__main__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_gen/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/_native.pyi
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/arrow_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/server.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/servicer.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.0 → chalk_remote_call_python-1.8.2}/chalk_remote_call/tracing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|