chalk-remote-call-python 1.8.7__tar.gz → 1.9.0__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.7/chalk_remote_call_python.egg-info → chalk_remote_call_python-1.9.0}/PKG-INFO +2 -1
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/README.md +1 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/Cargo.lock +7 -7
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/Cargo.toml +3 -3
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/self_consumer.rs +222 -61
- chalk_remote_call_python-1.9.0/chalk_remote_call/_version.py +1 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0/chalk_remote_call_python.egg-info}/PKG-INFO +2 -1
- chalk_remote_call_python-1.8.7/chalk_remote_call/_version.py +0 -1
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/MANIFEST.in +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/Cargo.toml +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/Cargo.toml +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.auth.v1.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.common.v1.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.tonic.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.utils.v1.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/descriptor.bin +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-proto/src/lib.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/async_service.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/coalesce.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/lib.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/metrics.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/python_bridge.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/server.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/chalk-remote-call-server/src/service.rs +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/rust-toolchain.toml +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/__main__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/auth/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/auth/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/common/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/common/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/runtime/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/runtime/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_native.pyi +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/arrow_utils.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/cli.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/handler_loader.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/input_transform.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/server.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/servicer.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/tracing.py +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call_python.egg-info/SOURCES.txt +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call_python.egg-info/dependency_links.txt +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call_python.egg-info/entry_points.txt +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call_python.egg-info/requires.txt +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call_python.egg-info/top_level.txt +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/pyproject.toml +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/setup.cfg +0 -0
- {chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chalk-remote-call-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0
|
|
4
4
|
Summary: Chalk remote call Python runtime interface client
|
|
5
5
|
Author: Chalk AI, Inc.
|
|
6
6
|
Project-URL: Homepage, https://chalk.ai
|
|
@@ -113,6 +113,7 @@ python -m chalk_remote_call --handler my_handler.handler
|
|
|
113
113
|
| Variable | Description |
|
|
114
114
|
|----------|-------------|
|
|
115
115
|
| `CHALK_INPUT_ARGS` | Comma-separated list of column names (e.g. `x,y,z`). Renames incoming RecordBatch columns by index. If unset, the original column names are used. Reserved columns (below) are held out of this mapping and keep their own name. |
|
|
116
|
+
| `CHALK_FNQ_QUEUE_PROTOCOL` | Self-consumer work transport: `list_v1` (default/backward compatible) or `stream_v1`. Deployment tooling sets this from immutable scaling-group revision metadata. |
|
|
116
117
|
|
|
117
118
|
#### Reserved columns
|
|
118
119
|
|
|
@@ -75,6 +75,7 @@ python -m chalk_remote_call --handler my_handler.handler
|
|
|
75
75
|
| Variable | Description |
|
|
76
76
|
|----------|-------------|
|
|
77
77
|
| `CHALK_INPUT_ARGS` | Comma-separated list of column names (e.g. `x,y,z`). Renames incoming RecordBatch columns by index. If unset, the original column names are used. Reserved columns (below) are held out of this mapping and keep their own name. |
|
|
78
|
+
| `CHALK_FNQ_QUEUE_PROTOCOL` | Self-consumer work transport: `list_v1` (default/backward compatible) or `stream_v1`. Deployment tooling sets this from immutable scaling-group revision metadata. |
|
|
78
79
|
|
|
79
80
|
#### Reserved columns
|
|
80
81
|
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk-remote-call-rs/Cargo.lock
RENAMED
|
@@ -484,7 +484,7 @@ dependencies = [
|
|
|
484
484
|
[[package]]
|
|
485
485
|
name = "chalk-core"
|
|
486
486
|
version = "0.0.0"
|
|
487
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
487
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
488
488
|
dependencies = [
|
|
489
489
|
"anyhow",
|
|
490
490
|
"envconfig",
|
|
@@ -499,7 +499,7 @@ dependencies = [
|
|
|
499
499
|
[[package]]
|
|
500
500
|
name = "chalk-protos"
|
|
501
501
|
version = "0.0.0"
|
|
502
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
502
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
503
503
|
dependencies = [
|
|
504
504
|
"prost 0.11.9",
|
|
505
505
|
"prost-build",
|
|
@@ -511,7 +511,7 @@ dependencies = [
|
|
|
511
511
|
[[package]]
|
|
512
512
|
name = "chalk-queue"
|
|
513
513
|
version = "0.0.0"
|
|
514
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
514
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
515
515
|
dependencies = [
|
|
516
516
|
"base64 0.22.1",
|
|
517
517
|
"redis",
|
|
@@ -560,7 +560,7 @@ dependencies = [
|
|
|
560
560
|
[[package]]
|
|
561
561
|
name = "chalk_metric_definitions"
|
|
562
562
|
version = "0.0.0"
|
|
563
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
563
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
564
564
|
dependencies = [
|
|
565
565
|
"chalk-protos",
|
|
566
566
|
"metrics-generator",
|
|
@@ -570,7 +570,7 @@ dependencies = [
|
|
|
570
570
|
[[package]]
|
|
571
571
|
name = "chalk_metrics"
|
|
572
572
|
version = "0.0.0"
|
|
573
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
573
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
574
574
|
dependencies = [
|
|
575
575
|
"async-trait",
|
|
576
576
|
"chalk-core",
|
|
@@ -604,7 +604,7 @@ dependencies = [
|
|
|
604
604
|
[[package]]
|
|
605
605
|
name = "chalk_statsd"
|
|
606
606
|
version = "0.0.0"
|
|
607
|
-
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=
|
|
607
|
+
source = "git+https://github.com/chalk-ai/chalk-private.git?rev=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
608
608
|
dependencies = [
|
|
609
609
|
"chalk-core",
|
|
610
610
|
"chrono",
|
|
@@ -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=783e9ce6b2c#783e9ce6b2c17563ab3302e5d11f8a664ed00232"
|
|
1871
1871
|
dependencies = [
|
|
1872
1872
|
"codegen",
|
|
1873
1873
|
"serde",
|
|
@@ -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 = "783e9ce6b2c" }
|
|
40
|
+
chalk_metrics = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "783e9ce6b2c" }
|
|
41
|
+
chalk_statsd = { git = "https://github.com/chalk-ai/chalk-private.git", rev = "783e9ce6b2c" }
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
//! This runs *alongside* the gRPC server, which is untouched: the synchronous
|
|
4
4
|
//! / direct `CallFunction` path keeps serving inbound calls.
|
|
5
5
|
//!
|
|
6
|
-
//!
|
|
6
|
+
//! Work is read from the revision's advertised Redis List or Stream transport.
|
|
7
|
+
//! Stream deliveries are acknowledged only after result writes complete and
|
|
8
|
+
//! reclaimed after a crashed owner stops heartbeating. Concurrency is capped
|
|
9
|
+
//! by a Redis-backed distributed semaphore (per function,
|
|
7
10
|
//! across every pod in the scaling group). The dispatch loop dispatches as fast
|
|
8
11
|
//! as it can acquire a slot and pop work; in-flight worker tasks are therefore
|
|
9
12
|
//! bounded by `max_concurrent`, not by traffic. A single per-pod renewer task
|
|
@@ -30,14 +33,17 @@
|
|
|
30
33
|
|
|
31
34
|
use std::collections::HashMap;
|
|
32
35
|
use std::panic::AssertUnwindSafe;
|
|
36
|
+
use std::str::FromStr;
|
|
33
37
|
use std::sync::{Arc, Mutex};
|
|
34
38
|
use std::time::{Duration, Instant};
|
|
35
39
|
|
|
36
40
|
use chalk_queue::semaphore::renew_many;
|
|
37
41
|
use chalk_queue::stream_writer;
|
|
38
42
|
use chalk_queue::types::QueuedCall;
|
|
39
|
-
use chalk_queue::{
|
|
40
|
-
|
|
43
|
+
use chalk_queue::{
|
|
44
|
+
BoundFunctionQueue, DequeuedCall, FunctionQueue, QueueProtocol, QueueReceipt, SemaphoreLease,
|
|
45
|
+
};
|
|
46
|
+
use dashmap::DashMap;
|
|
41
47
|
use futures_util::FutureExt;
|
|
42
48
|
use redis::aio::ConnectionManager;
|
|
43
49
|
use redis::Client;
|
|
@@ -59,6 +65,7 @@ const ENV_SEM_TTL_SECS: &str = "CHALK_FNQ_SEM_TTL_SECS";
|
|
|
59
65
|
const ENV_POLL_BACKOFF_INITIAL_MS: &str = "CHALK_FNQ_POLL_BACKOFF_INITIAL_MS";
|
|
60
66
|
const ENV_POLL_BACKOFF_MAX_SECS: &str = "CHALK_FNQ_POLL_BACKOFF_MAX_SECS";
|
|
61
67
|
const ENV_FLUSH_TIMEOUT_MS: &str = "CHALK_FNQ_FLUSH_TIMEOUT_MS";
|
|
68
|
+
const ENV_QUEUE_PROTOCOL: &str = "CHALK_FNQ_QUEUE_PROTOCOL";
|
|
62
69
|
|
|
63
70
|
/// Lease lifetime (default). Intentionally short relative to how long a call may run: the
|
|
64
71
|
/// per-pod renewer keeps a live call's lease alive (see module docs), so the
|
|
@@ -101,6 +108,7 @@ pub struct SelfConsumerConfig {
|
|
|
101
108
|
pub poll_backoff_initial: Duration,
|
|
102
109
|
pub poll_backoff_max: Duration,
|
|
103
110
|
pub flush_timeout: Duration,
|
|
111
|
+
pub queue_protocol: QueueProtocol,
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
impl SelfConsumerConfig {
|
|
@@ -162,6 +170,16 @@ impl SelfConsumerConfig {
|
|
|
162
170
|
.filter(|&n| n > 0)
|
|
163
171
|
.unwrap_or(DEFAULT_FLUSH_TIMEOUT_MS);
|
|
164
172
|
let flush_timeout = Duration::from_millis(flush_timeout_ms);
|
|
173
|
+
let queue_protocol = std::env::var(ENV_QUEUE_PROTOCOL)
|
|
174
|
+
.ok()
|
|
175
|
+
.filter(|value| !value.is_empty())
|
|
176
|
+
.map(|value| {
|
|
177
|
+
QueueProtocol::from_str(&value).unwrap_or_else(|error| {
|
|
178
|
+
warn!(%error, "invalid queue protocol; using legacy List transport");
|
|
179
|
+
QueueProtocol::ListV1
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
.unwrap_or_default();
|
|
165
183
|
|
|
166
184
|
Some(Self {
|
|
167
185
|
redis_url,
|
|
@@ -172,6 +190,7 @@ impl SelfConsumerConfig {
|
|
|
172
190
|
poll_backoff_initial,
|
|
173
191
|
poll_backoff_max,
|
|
174
192
|
flush_timeout,
|
|
193
|
+
queue_protocol,
|
|
175
194
|
})
|
|
176
195
|
}
|
|
177
196
|
}
|
|
@@ -179,7 +198,7 @@ impl SelfConsumerConfig {
|
|
|
179
198
|
/// Set of lease tokens this pod currently holds. The dispatch loop inserts a
|
|
180
199
|
/// token when it admits a call; the worker removes it on completion. The
|
|
181
200
|
/// renewer heartbeats whatever is in the set on each tick.
|
|
182
|
-
type
|
|
201
|
+
type LiveCalls = Arc<DashMap<String, QueueReceipt>>;
|
|
183
202
|
|
|
184
203
|
/// Connect to Redis and run the consume loop until the process exits. Returns
|
|
185
204
|
/// `Err` only on a fatal setup failure (bad URL / unreachable Redis at startup);
|
|
@@ -194,16 +213,32 @@ pub async fn run(
|
|
|
194
213
|
let client = Client::open(config.redis_url.clone())?;
|
|
195
214
|
let conn = ConnectionManager::new(client).await?;
|
|
196
215
|
let queue = FunctionQueue::new(conn.clone(), config.tenant.clone());
|
|
216
|
+
let input_queue = queue.bind(&config.function_name, config.queue_protocol);
|
|
217
|
+
let legacy_queue = (config.queue_protocol == QueueProtocol::StreamV1)
|
|
218
|
+
.then(|| queue.bind(&config.function_name, QueueProtocol::ListV1));
|
|
197
219
|
let sem = queue.semaphore(&config.function_name, config.max_concurrent, config.sem_ttl);
|
|
198
220
|
let sem_key = queue.sem_key_for(&config.function_name);
|
|
199
|
-
let
|
|
221
|
+
let live_calls: LiveCalls = Arc::new(DashMap::new());
|
|
222
|
+
let consumer_name = format!(
|
|
223
|
+
"{}:{}",
|
|
224
|
+
std::env::var("HOSTNAME").unwrap_or_else(|_| "fnq-shim".to_string()),
|
|
225
|
+
Uuid::new_v4()
|
|
226
|
+
);
|
|
200
227
|
|
|
201
|
-
spawn_renewer(
|
|
228
|
+
spawn_renewer(
|
|
229
|
+
input_queue.clone(),
|
|
230
|
+
conn.clone(),
|
|
231
|
+
sem_key,
|
|
232
|
+
live_calls.clone(),
|
|
233
|
+
config.sem_ttl,
|
|
234
|
+
);
|
|
202
235
|
|
|
203
236
|
info!(
|
|
204
237
|
function = %config.function_name,
|
|
205
238
|
tenant = %config.tenant,
|
|
206
239
|
max_concurrent = config.max_concurrent,
|
|
240
|
+
queue_protocol = config.queue_protocol.as_str(),
|
|
241
|
+
consumer = %consumer_name,
|
|
207
242
|
"fnq self-consumer started"
|
|
208
243
|
);
|
|
209
244
|
|
|
@@ -211,8 +246,9 @@ pub async fn run(
|
|
|
211
246
|
loop {
|
|
212
247
|
// Idle-gate: if there is no work, don't take (then immediately release)
|
|
213
248
|
// a semaphore slot — that churn would race genuine acquirers on other
|
|
214
|
-
// pods.
|
|
215
|
-
|
|
249
|
+
// pods. During a Stream rollout, also observe the legacy List so a new
|
|
250
|
+
// shim can drain work queued before its revision metadata changed.
|
|
251
|
+
match pending_depth(&input_queue, legacy_queue.as_ref()).await {
|
|
216
252
|
Ok(0) => {
|
|
217
253
|
tokio::time::sleep(backoff).await;
|
|
218
254
|
backoff = (backoff * 2).min(config.poll_backoff_max);
|
|
@@ -243,8 +279,15 @@ pub async fn run(
|
|
|
243
279
|
}
|
|
244
280
|
};
|
|
245
281
|
|
|
246
|
-
let
|
|
247
|
-
|
|
282
|
+
let delivery = match dequeue_next(
|
|
283
|
+
&input_queue,
|
|
284
|
+
legacy_queue.as_ref(),
|
|
285
|
+
&consumer_name,
|
|
286
|
+
config.sem_ttl,
|
|
287
|
+
)
|
|
288
|
+
.await
|
|
289
|
+
{
|
|
290
|
+
Ok(Some(delivery)) => delivery,
|
|
248
291
|
// Raced another consumer (or our own idle-gate) to an empty queue:
|
|
249
292
|
// give the slot back and retry.
|
|
250
293
|
Ok(None) => {
|
|
@@ -253,7 +296,7 @@ pub async fn run(
|
|
|
253
296
|
continue;
|
|
254
297
|
}
|
|
255
298
|
Err(e) => {
|
|
256
|
-
warn!(error = %e, "
|
|
299
|
+
warn!(error = %e, "dequeue failed; releasing slot");
|
|
257
300
|
let _ = lease.release().await;
|
|
258
301
|
backoff = (backoff * 2).min(config.poll_backoff_max);
|
|
259
302
|
continue;
|
|
@@ -264,7 +307,7 @@ pub async fn run(
|
|
|
264
307
|
|
|
265
308
|
// Register the token so the pod-level renewer heartbeats this lease
|
|
266
309
|
// while the call runs.
|
|
267
|
-
|
|
310
|
+
live_calls.insert(lease.token().to_string(), delivery.receipt.clone());
|
|
268
311
|
|
|
269
312
|
match &coalescing_queue {
|
|
270
313
|
// Batching on: route through the shared coalescing queue so this
|
|
@@ -273,11 +316,12 @@ pub async fn run(
|
|
|
273
316
|
Some(cq) => {
|
|
274
317
|
tokio::spawn(run_one_coalesced_call(
|
|
275
318
|
queue.clone(),
|
|
319
|
+
input_queue.clone(),
|
|
276
320
|
cq.clone(),
|
|
277
321
|
conn.clone(),
|
|
278
|
-
|
|
322
|
+
delivery,
|
|
279
323
|
lease,
|
|
280
|
-
|
|
324
|
+
live_calls.clone(),
|
|
281
325
|
metrics_pipeline.clone(),
|
|
282
326
|
));
|
|
283
327
|
}
|
|
@@ -286,10 +330,11 @@ pub async fn run(
|
|
|
286
330
|
tokio::spawn(run_one_call(
|
|
287
331
|
handler.clone(),
|
|
288
332
|
queue.clone(),
|
|
333
|
+
input_queue.clone(),
|
|
289
334
|
conn.clone(),
|
|
290
|
-
|
|
335
|
+
delivery,
|
|
291
336
|
lease,
|
|
292
|
-
|
|
337
|
+
live_calls.clone(),
|
|
293
338
|
config.flush_timeout,
|
|
294
339
|
metrics_pipeline.clone(),
|
|
295
340
|
));
|
|
@@ -300,6 +345,43 @@ pub async fn run(
|
|
|
300
345
|
}
|
|
301
346
|
}
|
|
302
347
|
|
|
348
|
+
async fn pending_depth(
|
|
349
|
+
queue: &BoundFunctionQueue,
|
|
350
|
+
legacy_queue: Option<&BoundFunctionQueue>,
|
|
351
|
+
) -> Result<u64, redis::RedisError> {
|
|
352
|
+
let selected = queue.current_depth().await?;
|
|
353
|
+
let legacy = match legacy_queue {
|
|
354
|
+
Some(queue) => queue.current_depth().await?,
|
|
355
|
+
None => 0,
|
|
356
|
+
};
|
|
357
|
+
Ok(selected + legacy)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async fn dequeue_next(
|
|
361
|
+
queue: &BoundFunctionQueue,
|
|
362
|
+
legacy_queue: Option<&BoundFunctionQueue>,
|
|
363
|
+
consumer_name: &str,
|
|
364
|
+
reclaim_idle: Duration,
|
|
365
|
+
) -> Result<Option<DequeuedCall>, Box<dyn std::error::Error + Send + Sync>> {
|
|
366
|
+
// Recovered work wins first. The legacy List is then drained before new
|
|
367
|
+
// Stream traffic; producers never route new work to both transports.
|
|
368
|
+
if let Some(reclaimed) = queue
|
|
369
|
+
.reclaim_stale(consumer_name, reclaim_idle, 1)
|
|
370
|
+
.await?
|
|
371
|
+
.into_iter()
|
|
372
|
+
.next()
|
|
373
|
+
{
|
|
374
|
+
return Ok(Some(reclaimed));
|
|
375
|
+
}
|
|
376
|
+
if let Some(legacy_queue) = legacy_queue {
|
|
377
|
+
if let Some(legacy) = legacy_queue.dequeue(consumer_name).await? {
|
|
378
|
+
info!(function = %queue.function_name(), "draining legacy List item during Stream migration");
|
|
379
|
+
return Ok(Some(legacy));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
queue.dequeue(consumer_name).await
|
|
383
|
+
}
|
|
384
|
+
|
|
303
385
|
/// Run a single queued call to completion, write its results to the call's
|
|
304
386
|
/// stream, then deregister + release its lease. Always releases the lease,
|
|
305
387
|
/// even if execution or stream writes fail or panic.
|
|
@@ -307,15 +389,20 @@ pub async fn run(
|
|
|
307
389
|
async fn run_one_call(
|
|
308
390
|
handler: Arc<PythonHandler>,
|
|
309
391
|
queue: FunctionQueue,
|
|
392
|
+
input_queue: BoundFunctionQueue,
|
|
310
393
|
mut conn: ConnectionManager,
|
|
311
|
-
|
|
394
|
+
delivery: DequeuedCall,
|
|
312
395
|
lease: SemaphoreLease,
|
|
313
|
-
|
|
396
|
+
live_calls: LiveCalls,
|
|
314
397
|
flush_timeout: Duration,
|
|
315
398
|
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
316
399
|
) {
|
|
400
|
+
let DequeuedCall {
|
|
401
|
+
call: work,
|
|
402
|
+
receipt,
|
|
403
|
+
} = delivery;
|
|
317
404
|
let call_id = work.call_id.clone();
|
|
318
|
-
match AssertUnwindSafe(execute_and_write(
|
|
405
|
+
let completed = match AssertUnwindSafe(execute_and_write(
|
|
319
406
|
&handler,
|
|
320
407
|
&queue,
|
|
321
408
|
&mut conn,
|
|
@@ -326,11 +413,12 @@ async fn run_one_call(
|
|
|
326
413
|
.catch_unwind()
|
|
327
414
|
.await
|
|
328
415
|
{
|
|
329
|
-
Ok(Ok(())) =>
|
|
416
|
+
Ok(Ok(())) => true,
|
|
330
417
|
Ok(Err(e)) => {
|
|
331
418
|
// The call's result stream may be incomplete; the call's 24h stream TTL
|
|
332
419
|
// and the meta status are the backstop for a stuck poller.
|
|
333
420
|
error!(call_id = %call_id, error = %e, "failed to execute/write queued call");
|
|
421
|
+
false
|
|
334
422
|
}
|
|
335
423
|
Err(panic_payload) => {
|
|
336
424
|
let panic_message = panic_payload
|
|
@@ -343,12 +431,41 @@ async fn run_one_call(
|
|
|
343
431
|
panic = %panic_message,
|
|
344
432
|
"panic while executing/writing queued call"
|
|
345
433
|
);
|
|
434
|
+
false
|
|
346
435
|
}
|
|
347
|
-
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
finish_delivery(
|
|
439
|
+
&input_queue,
|
|
440
|
+
&receipt,
|
|
441
|
+
completed,
|
|
442
|
+
&call_id,
|
|
443
|
+
lease,
|
|
444
|
+
&live_calls,
|
|
445
|
+
)
|
|
446
|
+
.await;
|
|
447
|
+
}
|
|
348
448
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
449
|
+
async fn finish_delivery(
|
|
450
|
+
queue: &BoundFunctionQueue,
|
|
451
|
+
receipt: &QueueReceipt,
|
|
452
|
+
completed: bool,
|
|
453
|
+
call_id: &str,
|
|
454
|
+
lease: SemaphoreLease,
|
|
455
|
+
live_calls: &LiveCalls,
|
|
456
|
+
) {
|
|
457
|
+
// Stop renewing before ack. If completion or ack failed, the Stream item
|
|
458
|
+
// becomes reclaimable after the idle timeout; List behavior is unchanged.
|
|
459
|
+
live_calls.remove(lease.token());
|
|
460
|
+
if completed {
|
|
461
|
+
match queue.acknowledge(receipt).await {
|
|
462
|
+
Ok(true) => {}
|
|
463
|
+
Ok(false) => warn!(%call_id, "delivery ownership was lost before acknowledgement"),
|
|
464
|
+
Err(error) => {
|
|
465
|
+
warn!(%call_id, %error, "delivery acknowledgement failed; item will be reclaimed")
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
352
469
|
if let Err(e) = lease.release().await {
|
|
353
470
|
warn!(call_id = %call_id, error = %e, "failed to release semaphore slot (will auto-recover after ttl)");
|
|
354
471
|
}
|
|
@@ -357,17 +474,23 @@ async fn run_one_call(
|
|
|
357
474
|
/// Coalesced counterpart to [`run_one_call`]: submit the call into the shared
|
|
358
475
|
/// [`CoalescingQueue`], write its single result blob to the call's stream, then
|
|
359
476
|
/// deregister + release its lease (always, even on failure).
|
|
477
|
+
#[allow(clippy::too_many_arguments)]
|
|
360
478
|
async fn run_one_coalesced_call(
|
|
361
479
|
queue: FunctionQueue,
|
|
480
|
+
input_queue: BoundFunctionQueue,
|
|
362
481
|
coalescing_queue: Arc<CoalescingQueue>,
|
|
363
482
|
mut conn: ConnectionManager,
|
|
364
|
-
|
|
483
|
+
delivery: DequeuedCall,
|
|
365
484
|
lease: SemaphoreLease,
|
|
366
|
-
|
|
485
|
+
live_calls: LiveCalls,
|
|
367
486
|
metrics_pipeline: Option<Arc<PublishingMetricsPipeline>>,
|
|
368
487
|
) {
|
|
488
|
+
let DequeuedCall {
|
|
489
|
+
call: work,
|
|
490
|
+
receipt,
|
|
491
|
+
} = delivery;
|
|
369
492
|
let call_id = work.call_id.clone();
|
|
370
|
-
|
|
493
|
+
let completed = match coalesced_execute_and_write(
|
|
371
494
|
&coalescing_queue,
|
|
372
495
|
&queue,
|
|
373
496
|
&mut conn,
|
|
@@ -376,17 +499,24 @@ async fn run_one_coalesced_call(
|
|
|
376
499
|
)
|
|
377
500
|
.await
|
|
378
501
|
{
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
502
|
+
Ok(()) => true,
|
|
503
|
+
Err(e) => {
|
|
504
|
+
// The call's result stream may be incomplete; the 24h stream TTL and
|
|
505
|
+
// the meta status are the backstop for a stuck poller.
|
|
506
|
+
error!(call_id = %call_id, error = %e, "failed to execute/write coalesced queued call");
|
|
507
|
+
false
|
|
508
|
+
}
|
|
509
|
+
};
|
|
383
510
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
511
|
+
finish_delivery(
|
|
512
|
+
&input_queue,
|
|
513
|
+
&receipt,
|
|
514
|
+
completed,
|
|
515
|
+
&call_id,
|
|
516
|
+
lease,
|
|
517
|
+
&live_calls,
|
|
518
|
+
)
|
|
519
|
+
.await;
|
|
390
520
|
}
|
|
391
521
|
|
|
392
522
|
/// Submit one call into the shared coalescing queue and relay its single
|
|
@@ -666,14 +796,15 @@ async fn flush_new(
|
|
|
666
796
|
|
|
667
797
|
/// Spawn the single per-pod renewer: every `SEM_RENEW_INTERVAL` it heartbeats
|
|
668
798
|
/// all currently-held lease tokens in one `renew_many` round-trip. A reclaimed
|
|
669
|
-
/// token means this pod stalled past `sem_ttl` without renewing
|
|
670
|
-
///
|
|
671
|
-
///
|
|
672
|
-
///
|
|
799
|
+
/// token means this pod stalled past `sem_ttl` without renewing. Stream
|
|
800
|
+
/// receipts are renewed in grouped round trips too; ownership loss is surfaced
|
|
801
|
+
/// because a GIL-blocked handler cannot be aborted, while the reclaimed call may
|
|
802
|
+
/// already be running on another pod.
|
|
673
803
|
fn spawn_renewer(
|
|
804
|
+
queue: BoundFunctionQueue,
|
|
674
805
|
mut conn: ConnectionManager,
|
|
675
806
|
sem_key: String,
|
|
676
|
-
|
|
807
|
+
live_calls: LiveCalls,
|
|
677
808
|
sem_ttl: Duration,
|
|
678
809
|
) {
|
|
679
810
|
tokio::spawn(async move {
|
|
@@ -681,7 +812,11 @@ fn spawn_renewer(
|
|
|
681
812
|
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
|
682
813
|
loop {
|
|
683
814
|
ticker.tick().await;
|
|
684
|
-
let
|
|
815
|
+
let active: Vec<(String, QueueReceipt)> = live_calls
|
|
816
|
+
.iter()
|
|
817
|
+
.map(|entry| (entry.key().clone(), entry.value().clone()))
|
|
818
|
+
.collect();
|
|
819
|
+
let tokens: Vec<String> = active.iter().map(|(token, _)| token.clone()).collect();
|
|
685
820
|
if tokens.is_empty() {
|
|
686
821
|
continue;
|
|
687
822
|
}
|
|
@@ -695,6 +830,16 @@ fn spawn_renewer(
|
|
|
695
830
|
Ok(_) => {}
|
|
696
831
|
Err(e) => warn!(error = %e, "batch lease renew failed"),
|
|
697
832
|
}
|
|
833
|
+
let receipts: Vec<QueueReceipt> =
|
|
834
|
+
active.into_iter().map(|(_, receipt)| receipt).collect();
|
|
835
|
+
match queue.heartbeat_many(&receipts).await {
|
|
836
|
+
Ok(lost) if !lost.is_empty() => warn!(
|
|
837
|
+
count = lost.len(),
|
|
838
|
+
"Stream deliveries reclaimed while calls were still running"
|
|
839
|
+
),
|
|
840
|
+
Ok(_) => {}
|
|
841
|
+
Err(error) => warn!(%error, "batch Stream delivery renewal failed"),
|
|
842
|
+
}
|
|
698
843
|
}
|
|
699
844
|
});
|
|
700
845
|
}
|
|
@@ -736,6 +881,7 @@ mod tests {
|
|
|
736
881
|
std::env::remove_var(ENV_POLL_BACKOFF_INITIAL_MS);
|
|
737
882
|
std::env::remove_var(ENV_POLL_BACKOFF_MAX_SECS);
|
|
738
883
|
std::env::remove_var(ENV_FLUSH_TIMEOUT_MS);
|
|
884
|
+
std::env::remove_var(ENV_QUEUE_PROTOCOL);
|
|
739
885
|
|
|
740
886
|
let config = SelfConsumerConfig::from_env().expect("config should parse");
|
|
741
887
|
assert_eq!(config.sem_ttl, Duration::from_secs(DEFAULT_SEM_TTL_SECS));
|
|
@@ -751,6 +897,7 @@ mod tests {
|
|
|
751
897
|
config.flush_timeout,
|
|
752
898
|
Duration::from_millis(DEFAULT_FLUSH_TIMEOUT_MS)
|
|
753
899
|
);
|
|
900
|
+
assert_eq!(config.queue_protocol, QueueProtocol::ListV1);
|
|
754
901
|
}
|
|
755
902
|
|
|
756
903
|
#[test]
|
|
@@ -785,6 +932,20 @@ mod tests {
|
|
|
785
932
|
assert_eq!(config.max_concurrent, 1);
|
|
786
933
|
}
|
|
787
934
|
|
|
935
|
+
#[test]
|
|
936
|
+
fn test_stream_queue_protocol_from_env() {
|
|
937
|
+
let _env = lock_env();
|
|
938
|
+
|
|
939
|
+
std::env::set_var(ENV_REDIS_URL, "redis://localhost");
|
|
940
|
+
std::env::set_var(ENV_TENANT, "test_tenant");
|
|
941
|
+
std::env::set_var(ENV_FUNCTION_NAME, "test_fn");
|
|
942
|
+
std::env::set_var(ENV_QUEUE_PROTOCOL, "stream_v1");
|
|
943
|
+
|
|
944
|
+
let config = SelfConsumerConfig::from_env().expect("config should parse");
|
|
945
|
+
assert_eq!(config.queue_protocol, QueueProtocol::StreamV1);
|
|
946
|
+
std::env::remove_var(ENV_QUEUE_PROTOCOL);
|
|
947
|
+
}
|
|
948
|
+
|
|
788
949
|
#[test]
|
|
789
950
|
fn test_invalid_timeout_values_use_defaults() {
|
|
790
951
|
let _env = lock_env();
|
|
@@ -894,7 +1055,7 @@ mod tests {
|
|
|
894
1055
|
|
|
895
1056
|
// Verify notify_handle can be cloned (Arc behavior)
|
|
896
1057
|
let _notify_handle_clone = notify_handle.clone();
|
|
897
|
-
|
|
1058
|
+
assert!(!std::ptr::eq(¬ify_handle, &_notify_handle_clone));
|
|
898
1059
|
// But they should point to the same underlying Notify
|
|
899
1060
|
}
|
|
900
1061
|
|
|
@@ -977,42 +1138,42 @@ mod tests {
|
|
|
977
1138
|
// Integration tests for live token tracking and core dispatch logic
|
|
978
1139
|
#[tokio::test]
|
|
979
1140
|
async fn test_live_tokens_insert_and_remove() {
|
|
980
|
-
let
|
|
1141
|
+
let live_calls: LiveCalls = Arc::new(DashMap::new());
|
|
981
1142
|
let token1 = "lease-token-1";
|
|
982
1143
|
let token2 = "lease-token-2";
|
|
983
1144
|
|
|
984
1145
|
// Simulate dispatch: register tokens as calls are admitted
|
|
985
|
-
|
|
986
|
-
|
|
1146
|
+
live_calls.insert(token1.to_string(), QueueReceipt::ListV1);
|
|
1147
|
+
live_calls.insert(token2.to_string(), QueueReceipt::ListV1);
|
|
987
1148
|
|
|
988
|
-
assert!(
|
|
989
|
-
assert!(
|
|
990
|
-
assert_eq!(
|
|
1149
|
+
assert!(live_calls.contains_key(token1));
|
|
1150
|
+
assert!(live_calls.contains_key(token2));
|
|
1151
|
+
assert_eq!(live_calls.iter().count(), 2, "should track both tokens");
|
|
991
1152
|
|
|
992
1153
|
// Simulate cleanup: remove as calls complete
|
|
993
|
-
|
|
994
|
-
assert!(!
|
|
995
|
-
assert!(
|
|
996
|
-
assert_eq!(
|
|
1154
|
+
live_calls.remove(token1);
|
|
1155
|
+
assert!(!live_calls.contains_key(token1));
|
|
1156
|
+
assert!(live_calls.contains_key(token2));
|
|
1157
|
+
assert_eq!(live_calls.iter().count(), 1);
|
|
997
1158
|
|
|
998
1159
|
// Final cleanup
|
|
999
|
-
|
|
1000
|
-
assert_eq!(
|
|
1160
|
+
live_calls.remove(token2);
|
|
1161
|
+
assert_eq!(live_calls.iter().count(), 0, "all tokens cleaned up");
|
|
1001
1162
|
}
|
|
1002
1163
|
|
|
1003
1164
|
#[tokio::test]
|
|
1004
1165
|
async fn test_live_tokens_concurrent_access() {
|
|
1005
|
-
let
|
|
1166
|
+
let live_calls: LiveCalls = Arc::new(DashMap::new());
|
|
1006
1167
|
let mut handles = vec![];
|
|
1007
1168
|
|
|
1008
1169
|
// Spawn 10 tasks that each insert and remove a token
|
|
1009
1170
|
for i in 0..10 {
|
|
1010
|
-
let
|
|
1171
|
+
let calls = live_calls.clone();
|
|
1011
1172
|
let handle = tokio::spawn(async move {
|
|
1012
1173
|
let token = format!("token-{}", i);
|
|
1013
|
-
|
|
1174
|
+
calls.insert(token.clone(), QueueReceipt::ListV1);
|
|
1014
1175
|
tokio::time::sleep(Duration::from_millis(1)).await;
|
|
1015
|
-
|
|
1176
|
+
calls.remove(&token);
|
|
1016
1177
|
});
|
|
1017
1178
|
handles.push(handle);
|
|
1018
1179
|
}
|
|
@@ -1024,7 +1185,7 @@ mod tests {
|
|
|
1024
1185
|
|
|
1025
1186
|
// All tokens should be cleaned up
|
|
1026
1187
|
assert_eq!(
|
|
1027
|
-
|
|
1188
|
+
live_calls.iter().count(),
|
|
1028
1189
|
0,
|
|
1029
1190
|
"concurrent inserts/removes should leave set empty"
|
|
1030
1191
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.9.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chalk-remote-call-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0
|
|
4
4
|
Summary: Chalk remote call Python runtime interface client
|
|
5
5
|
Author: Chalk AI, Inc.
|
|
6
6
|
Project-URL: Homepage, https://chalk.ai
|
|
@@ -113,6 +113,7 @@ python -m chalk_remote_call --handler my_handler.handler
|
|
|
113
113
|
| Variable | Description |
|
|
114
114
|
|----------|-------------|
|
|
115
115
|
| `CHALK_INPUT_ARGS` | Comma-separated list of column names (e.g. `x,y,z`). Renames incoming RecordBatch columns by index. If unset, the original column names are used. Reserved columns (below) are held out of this mapping and keep their own name. |
|
|
116
|
+
| `CHALK_FNQ_QUEUE_PROTOCOL` | Self-consumer work transport: `list_v1` (default/backward compatible) or `stream_v1`. Deployment tooling sets this from immutable scaling-group revision metadata. |
|
|
116
117
|
|
|
117
118
|
#### Reserved columns
|
|
118
119
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.8.7"
|
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/__init__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/__main__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/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.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/_native.pyi
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/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.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/server.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/chalk_remote_call/servicer.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.8.7 → chalk_remote_call_python-1.9.0}/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
|