chalk-remote-call-python 1.7.1__tar.gz → 1.7.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.7.1 → chalk_remote_call_python-1.7.2}/PKG-INFO +1 -1
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/async_service.rs +65 -7
- chalk_remote_call_python-1.7.2/chalk_remote_call/_version.py +1 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/PKG-INFO +1 -1
- chalk_remote_call_python-1.7.1/chalk_remote_call/_version.py +0 -1
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/MANIFEST.in +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/README.md +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/Cargo.lock +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/Cargo.toml +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/Cargo.toml +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.auth.v1.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.common.v1.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.runtime.v1.tonic.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/chalk.utils.v1.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/gen/descriptor.bin +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-proto/src/lib.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/Cargo.toml +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/coalesce.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/lib.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/python_bridge.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/server.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/chalk-remote-call-server/src/service.rs +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/rust-toolchain.toml +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/__main__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/auth/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/auth/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/auth/v1/permissions_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/common/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/common/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/common/v1/chalk_error_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/runtime/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/runtime/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/runtime/v1/remote_python_call_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/__init__.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/encoding_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/field_change_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_gen/chalk/utils/v1/sensitive_pb2_grpc.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_native.pyi +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/arrow_utils.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/cli.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/handler_loader.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/input_transform.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/server.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/servicer.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/tracing.py +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/SOURCES.txt +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/dependency_links.txt +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/entry_points.txt +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/requires.txt +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call_python.egg-info/top_level.txt +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/pyproject.toml +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/setup.cfg +0 -0
- {chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/setup.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
3
3
|
use std::sync::{Arc, Mutex};
|
|
4
|
+
use std::time::{Duration, Instant};
|
|
4
5
|
|
|
5
6
|
use chalk_remote_call_proto::chalk::common::v1::ChalkError;
|
|
6
7
|
use chalk_remote_call_proto::chalk::runtime::v1::async_remote_call_service_server::AsyncRemoteCallService;
|
|
@@ -14,6 +15,14 @@ use tracing::{debug, error, info, instrument};
|
|
|
14
15
|
use crate::python_bridge::{ChunkBuffer, PythonHandler};
|
|
15
16
|
use crate::service::extract_metadata;
|
|
16
17
|
|
|
18
|
+
/// How often the orphan sweeper runs.
|
|
19
|
+
const SWEEP_INTERVAL: Duration = Duration::from_secs(30);
|
|
20
|
+
/// How long a *terminal* entry is retained before the sweeper reclaims it. Only
|
|
21
|
+
/// matters for orphans — calls the consumer drained are evicted immediately on
|
|
22
|
+
/// their terminal poll. Comfortably larger than the consumer's poll cadence so
|
|
23
|
+
/// the sweeper never races a live consumer that is about to read a result.
|
|
24
|
+
const RETENTION: Duration = Duration::from_mins(30);
|
|
25
|
+
|
|
17
26
|
/// In-memory execution record for one enqueued call.
|
|
18
27
|
///
|
|
19
28
|
/// Lives only on the sg pod that accepted the `EnqueueRemoteCall`, and is lost
|
|
@@ -31,6 +40,9 @@ struct CallState {
|
|
|
31
40
|
chunks: ChunkBuffer,
|
|
32
41
|
/// Populated only when `status == Failed`; surfaced as a `ChalkError`.
|
|
33
42
|
error: Option<String>,
|
|
43
|
+
/// When the call reached a terminal status. Used only by the orphan sweeper
|
|
44
|
+
/// to decide when an un-drained terminal entry is safe to reclaim.
|
|
45
|
+
completed_at: Option<Instant>,
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
impl CallState {
|
|
@@ -39,12 +51,20 @@ impl CallState {
|
|
|
39
51
|
status: RemoteCallStatus::Pending,
|
|
40
52
|
chunks: Arc::new(Mutex::new(Vec::new())),
|
|
41
53
|
error: None,
|
|
54
|
+
completed_at: None,
|
|
42
55
|
}
|
|
43
56
|
}
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
type Registry = Arc<Mutex<HashMap<String, CallState>>>;
|
|
47
60
|
|
|
61
|
+
fn is_terminal(status: RemoteCallStatus) -> bool {
|
|
62
|
+
matches!(
|
|
63
|
+
status,
|
|
64
|
+
RemoteCallStatus::Completed | RemoteCallStatus::Failed
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
/// Async (enqueue + poll) executor for the scaling-group hop.
|
|
49
69
|
///
|
|
50
70
|
/// `EnqueueRemoteCall` runs the handler in a detached background task that
|
|
@@ -53,6 +73,11 @@ type Registry = Arc<Mutex<HashMap<String, CallState>>>;
|
|
|
53
73
|
/// function execution from any single connection's lifetime, so the path is
|
|
54
74
|
/// immune to gateway request/stream timeouts — every RPC here is sub-second
|
|
55
75
|
/// regardless of how long the function runs.
|
|
76
|
+
///
|
|
77
|
+
/// Entries are reclaimed two ways: the terminal poll that delivers a result
|
|
78
|
+
/// evicts its own entry (the consumer drains a call exactly once, then persists
|
|
79
|
+
/// to Redis and stops polling it), and a background sweeper reclaims orphans —
|
|
80
|
+
/// calls that finished but whose consumer died before the terminal poll.
|
|
56
81
|
pub struct AsyncRemoteCallServiceImpl {
|
|
57
82
|
python_handler: Arc<PythonHandler>,
|
|
58
83
|
registry: Registry,
|
|
@@ -66,9 +91,13 @@ pub struct AsyncRemoteCallServiceImpl {
|
|
|
66
91
|
|
|
67
92
|
impl AsyncRemoteCallServiceImpl {
|
|
68
93
|
pub fn new(python_handler: Arc<PythonHandler>, batching_enabled: bool) -> Self {
|
|
94
|
+
let registry: Registry = Arc::new(Mutex::new(HashMap::new()));
|
|
95
|
+
// Runs inside the server's tokio runtime (the service is constructed
|
|
96
|
+
// within `run_server`); reclaims orphaned terminal entries.
|
|
97
|
+
spawn_sweeper(registry.clone());
|
|
69
98
|
Self {
|
|
70
99
|
python_handler,
|
|
71
|
-
registry
|
|
100
|
+
registry,
|
|
72
101
|
next_id: AtomicU64::new(1),
|
|
73
102
|
batching_enabled,
|
|
74
103
|
}
|
|
@@ -138,6 +167,7 @@ impl AsyncRemoteCallService for AsyncRemoteCallServiceImpl {
|
|
|
138
167
|
|
|
139
168
|
let mut reg = registry.lock().expect("registry mutex poisoned");
|
|
140
169
|
if let Some(s) = reg.get_mut(&id) {
|
|
170
|
+
s.completed_at = Some(Instant::now());
|
|
141
171
|
match result {
|
|
142
172
|
Ok(()) => {
|
|
143
173
|
s.status = RemoteCallStatus::Completed;
|
|
@@ -170,16 +200,23 @@ impl AsyncRemoteCallService for AsyncRemoteCallServiceImpl {
|
|
|
170
200
|
.map_err(|_| Status::invalid_argument(format!("invalid cursor: {}", req.cursor)))?
|
|
171
201
|
};
|
|
172
202
|
|
|
173
|
-
// Read status/error and grab the chunk-buffer handle under the map lock
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
203
|
+
// Read status/error and grab the chunk-buffer handle under the map lock.
|
|
204
|
+
// `status` reaches a terminal value only after the handler returns (all
|
|
205
|
+
// chunks already appended), so seeing `Completed`/`Failed` guarantees
|
|
206
|
+
// the buffer is complete — and this poll delivers it in full. Since the
|
|
207
|
+
// consumer drains a call to terminal exactly once (then persists to
|
|
208
|
+
// Redis and never re-polls this call_id), we evict the entry here. The
|
|
209
|
+
// cloned `chunks` Arc keeps the buffer alive for the read below.
|
|
177
210
|
let (status, error, chunks) = {
|
|
178
|
-
let reg = self.registry.lock().expect("registry mutex poisoned");
|
|
211
|
+
let mut reg = self.registry.lock().expect("registry mutex poisoned");
|
|
179
212
|
let state = reg
|
|
180
213
|
.get(&req.call_id)
|
|
181
214
|
.ok_or_else(|| Status::not_found(format!("unknown call_id: {}", req.call_id)))?;
|
|
182
|
-
(state.status, state.error.clone(), state.chunks.clone())
|
|
215
|
+
let snapshot = (state.status, state.error.clone(), state.chunks.clone());
|
|
216
|
+
if is_terminal(snapshot.0) {
|
|
217
|
+
reg.remove(&req.call_id);
|
|
218
|
+
}
|
|
219
|
+
snapshot
|
|
183
220
|
};
|
|
184
221
|
|
|
185
222
|
let buf = chunks.lock().expect("chunk buffer poisoned");
|
|
@@ -236,3 +273,24 @@ fn set_status(registry: &Registry, call_id: &str, status: RemoteCallStatus) {
|
|
|
236
273
|
}
|
|
237
274
|
}
|
|
238
275
|
}
|
|
276
|
+
|
|
277
|
+
/// Background task: periodically reclaim *orphaned* terminal entries — calls
|
|
278
|
+
/// that finished but whose consumer died before issuing the terminal poll that
|
|
279
|
+
/// would normally evict them. Entries the consumer drains are removed on their
|
|
280
|
+
/// terminal poll and never reach the sweeper; non-terminal entries (still
|
|
281
|
+
/// running) are never reclaimed here.
|
|
282
|
+
fn spawn_sweeper(registry: Registry) {
|
|
283
|
+
tokio::spawn(async move {
|
|
284
|
+
let mut ticker = tokio::time::interval(SWEEP_INTERVAL);
|
|
285
|
+
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
|
286
|
+
loop {
|
|
287
|
+
ticker.tick().await;
|
|
288
|
+
let Ok(mut reg) = registry.lock() else {
|
|
289
|
+
continue;
|
|
290
|
+
};
|
|
291
|
+
reg.retain(|_, s| {
|
|
292
|
+
!(is_terminal(s.status) && s.completed_at.is_some_and(|t| t.elapsed() > RETENTION))
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.7.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.7.1"
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk-remote-call-rs/Cargo.lock
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/__init__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/__main__.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.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.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/_native.pyi
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.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.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/server.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.2}/chalk_remote_call/servicer.py
RENAMED
|
File without changes
|
{chalk_remote_call_python-1.7.1 → chalk_remote_call_python-1.7.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
|