Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
7de32de
feat(memory-pool): add NetworkZenohTransport path for cross-machine t…
tang-canran Jul 31, 2026
d0c88e5
feat(memory-pool): add cross-machine event types and proxy pool storage
tang-canran Jul 31, 2026
c3f9ec5
feat(memory-pool): cross-machine write/read via daemon proxy pool
tang-canran Jul 31, 2026
8ae663f
refactor(memory-pool): simplify WriteMemoryPool handler, defer Zenoh …
tang-canran Jul 31, 2026
38200b6
feat(memory-pool): Zenoh cross-machine forwarding for memory pool writes
tang-canran Jul 31, 2026
2c2f2e6
feat(memory-pool): propagate tensor dtype/shape through cross-machine…
tang-canran Aug 3, 2026
d68d2fb
fix(daemon): keep memory-pool zenoh I/O off the event loop, fail loud…
tang-canran Aug 3, 2026
7b8c4d3
fix(replay-node,cli): handle InterDaemonEvent::MemoryPoolWrite in mat…
tang-canran Aug 3, 2026
51db279
feat(api-python): push registered pool data through daemon proxy for …
tang-canran Aug 3, 2026
783a459
test(memory-pool): cross-machine sender re-push/pacing and receiver r…
tang-canran Aug 3, 2026
fb744c9
fix(api-python): proxy read must point at the PyBytes payload, not th…
tang-canran Aug 3, 2026
582f070
fix(memory-pool): unblock cross-machine multi-frame loop
tang-canran Aug 3, 2026
a71ad57
fix(memory-pool): measure cross-machine throughput on wall clock, not…
tang-canran Aug 3, 2026
0a61315
docs: cross-machine memory pool zenoh direct-write design (v1: cpu2cpu)
tang-canran Aug 3, 2026
40cd40b
docs: unresolvable machine -> register is a full no-op (warn only)
tang-canran Aug 3, 2026
e83e0d7
docs: both register failure modes warn-and-no-op; messages differ
tang-canran Aug 3, 2026
99739ac
docs: drop lazy pool creation on write — synchronous register guarant…
tang-canran Aug 3, 2026
de83418
docs: implementation plan for cross-machine zenoh pool direct-write path
tang-canran Aug 3, 2026
4b93d9f
feat(message): cross-machine pool register/ack/free events + ResolveM…
tang-canran Aug 3, 2026
1a30657
fix(message): stub arms for new cross-machine pool variants (workspac…
tang-canran Aug 3, 2026
6dac00d
feat(coordinator): resolve machine id to registered daemon
tang-canran Aug 3, 2026
a8d7e9e
fix(coordinator): warn on ResolveMachine store errors
tang-canran Aug 3, 2026
02b645e
feat(daemon): sync cross-machine register with spawned ack wait
tang-canran Aug 3, 2026
7ad0bb1
fix(daemon): unwrap ResolveMachineResult layer in resolve_machine
tang-canran Aug 3, 2026
1ba1019
fix(daemon): route ResolveMachine reply via caller-controlled id
tang-canran Aug 3, 2026
ccff518
feat(daemon): mirror cross-machine pools, direct seqlock writes, dual…
tang-canran Aug 3, 2026
20548f8
fix(daemon): remote-only memory-pool publishes + mirror guards
tang-canran Aug 3, 2026
8ded354
feat(api-python): register_memory_pool machine param with sync cross-…
tang-canran Aug 3, 2026
1d25965
fix(api-python): roll back + return None on transport failure too
tang-canran Aug 3, 2026
7964b07
feat(daemon): forward cross-machine free to the peer daemon
tang-canran Aug 3, 2026
c31fdcb
test(memory-pool): cross-machine register via machine param
tang-canran Aug 3, 2026
a0e5f50
fix(daemon): receiver-side free releases the cross-machine mirror
tang-canran Aug 3, 2026
3dd661d
fix(daemon): cross-machine FreePool releases the origin's local pool
tang-canran Aug 3, 2026
1758798
docs: mark cross-machine pool v1 implemented (cpu2cpu)
tang-canran Aug 3, 2026
fbd894b
fix(memory-pool): orphan cleanup also matches machine-qualified mirro…
tang-canran Aug 3, 2026
96e8966
docs: WAN verification — 32.8 MB/s end-to-end (2.5x vs proxy path)
tang-canran Aug 4, 2026
342be9b
refactor(memory-pool): targeted cross-machine free via peer tracking …
tang-canran Aug 4, 2026
2b8a047
fix(daemon): retry RegisterPool publish on ack timeout
tang-canran Aug 4, 2026
633461f
fix(daemon): declare memory-pool subscription before the node build
tang-canran Aug 4, 2026
0255f60
refactor(memory-pool): remove legacy proxy path (PROXY_POOL_DATA + hex)
tang-canran Aug 4, 2026
32ea4cd
feat(daemon): serialise mirror writes per-pool + gate origin forward …
tang-canran Aug 4, 2026
4ac276a
docs: mark mirror-write serialization and origin gate complete in spec
tang-canran Aug 4, 2026
33b3876
refactor(memory-pool): merge cross-machine pool tracking into MemoryP…
tang-canran Aug 5, 2026
5e333fc
docs: record cross_pools merge into MemoryPoolManager
tang-canran Aug 5, 2026
59c046f
feat(memory-pool): stale segment recovery — EEXIST retry + startup or…
tang-canran Aug 5, 2026
8a69944
feat(api-python): register_memory_pool name param + machine-qualified…
tang-canran Aug 5, 2026
53d7c6a
docs: record name param + machine-qualified segment names
tang-canran Aug 5, 2026
2d3dbef
feat(memory-pool): same-host cross-daemon direct read + skip no-mirro…
tang-canran Aug 5, 2026
d95ef15
docs: record same-host direct read + skip push
tang-canran Aug 5, 2026
2134e3f
feat(memory-pool): same-host direct detection — skip the data push
tang-canran Aug 5, 2026
063f3f2
docs: record same-host direct detection
tang-canran Aug 5, 2026
7dc743d
test(memory-pool): cross-machine example uses per-frame handshake, no…
tang-canran Aug 6, 2026
95e7358
feat(daemon): memory-pool control notifications over zenoh SHM
tang-canran Aug 7, 2026
9e5c05e
feat(memory-pool): cross-machine GPU pools via CPU staging pools
tang-canran Aug 7, 2026
90d3bcc
examples(memory-pool): add cross_machine env and working_dir to cross…
tang-canran Aug 7, 2026
b31428e
feat(memory-pool): same-host GPU cross-machine pools export IPC handle
tang-canran Aug 7, 2026
856dd7c
examples(memory-pool): drop registration re-push, guard first read
tang-canran Aug 7, 2026
990d21b
merge: resolve conflicts with upstream main
tang-canran Aug 8, 2026
083245f
restore upstream's docs/superpowers (rmw-zenoh-full-parity); keep onl…
tang-canran Aug 8, 2026
623dd77
fix: cargo fmt + rename ue->e (typos) from CI
tang-canran Aug 8, 2026
625b01b
fix: address automated review (7 points)
tang-canran Aug 9, 2026
839635c
style: cargo fmt
tang-canran Aug 9, 2026
f84aedc
test: add cross-daemon memory-pool smoke test; fix two bugs it caught
tang-canran Aug 9, 2026
170278f
fix: gate retry window on local-host vs remote; strengthen smoke succ…
tang-canran Aug 9, 2026
33a7c7b
Merge remote-tracking branch 'upstream/main' into tmp-merge
tang-canran Aug 10, 2026
3c88617
fix: scope cleanup_orphans sweep to own machine on same-host multi-da…
tang-canran Aug 10, 2026
c83c59b
fix: address human review (5 issues: write commit ack, 64MiB cap, dat…
tang-canran Aug 11, 2026
56dcc79
fix: cover MemoryPoolWriteAck in replay-node's inter-daemon match
tang-canran Aug 11, 2026
f420a54
fix: shared-memory-reference cross-machine write (completes P1-2's al…
tang-canran Aug 11, 2026
c7d2a8e
test: pin write-commit ack semantics; fix hardcoded 3600s message
tang-canran Aug 11, 2026
263b09e
docs(memory-pool): document same-host and cross-machine usage
tang-canran Aug 11, 2026
da17ba2
fix: off-loop shmem read, mirror allocation cap, escaped header JSON
tang-canran Aug 11, 2026
0140fee
docs(memory-pool): drop speed numbers from README, point to design.md
tang-canran Aug 11, 2026
c13d9b8
feat: direct-TCP cross-machine data plane (one user-space copy)
tang-canran Aug 11, 2026
a56472a
fix: bound accept-loop retry on persistent errors; test the direct-TC…
tang-canran Aug 11, 2026
dbee784
refactor: open the direct-TCP data listener lazily
tang-canran Aug 11, 2026
1b9f9d3
feat: advertise the mirror's dialable address in RegisterPoolAck
tang-canran Aug 11, 2026
faf72d0
test: cover the zenoh ack publish with an in-process loopback round-trip
tang-canran Aug 11, 2026
dcd9cfd
fix: warn once per pool on direct-TCP degradation; log recovery once
tang-canran Aug 11, 2026
e2c1e7b
ci: retrigger CI (Check job hung on the previous run)
tang-canran Aug 11, 2026
84f11f7
fix: reject wire-controlled size overflow; fail origin fast on mirror…
tang-canran Aug 12, 2026
7681b92
docs: fix stale comment on the payload-read failure path
tang-canran Aug 12, 2026
4263db0
fix: scope the direct-write lock by (dataflow, pool) like the other c…
tang-canran Aug 12, 2026
f07da08
fix: drain per-dataflow cross-write state in finish_dataflow
tang-canran Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
804 changes: 708 additions & 96 deletions apis/python/node/src/lib.rs

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion apis/rust/node/src/daemon_connection/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ impl InteractiveEvents {
}
DaemonRequest::RegisterPinnedMemory { .. }
| DaemonRequest::ReadPinnedMemory { .. }
| DaemonRequest::FreePinnedMemory { .. } => DaemonReply::Result(Ok(())),
| DaemonRequest::FreePinnedMemory { .. }
| DaemonRequest::WritePinnedMemory { .. } => DaemonReply::Result(Ok(())),
DaemonRequest::RegisterCrossMachinePool { .. } => {
eyre::bail!("cross-machine pool registration is not supported in interactive mode")
}
DaemonRequest::NodeConfig { .. } => {
eyre::bail!("unexpected NodeConfig in interactive mode")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,13 @@ impl IntegrationTestingEvents {
}
DaemonRequest::RegisterPinnedMemory { .. }
| DaemonRequest::ReadPinnedMemory { .. }
| DaemonRequest::FreePinnedMemory { .. } => DaemonReply::Result(Ok(())),
| DaemonRequest::FreePinnedMemory { .. }
| DaemonRequest::WritePinnedMemory { .. } => DaemonReply::Result(Ok(())),
DaemonRequest::RegisterCrossMachinePool { .. } => {
eyre::bail!(
"cross-machine pool registration is not supported in integration-testing mode"
)
}
DaemonRequest::NodeConfig { .. } => {
eyre::bail!("unexpected NodeConfig in interactive mode")
}
Expand Down
61 changes: 61 additions & 0 deletions apis/rust/node/src/node/control_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,65 @@ impl ControlChannel {
other => bail!("unexpected FreePinnedMemory reply: {other:?}"),
}
}

pub fn write_pinned_memory(
&mut self,
shared_memory_id: String,
tensor_data: Vec<u8>,
size: usize,
) -> eyre::Result<()> {
let request = DaemonRequest::WritePinnedMemory {
shared_memory_id,
tensor_data,
size,
};
let reply = self
.channel
.request(&Timestamped {
inner: request,
timestamp: self.clock.new_timestamp(),
})
.wrap_err("failed to send WritePinnedMemory request to dora-daemon")?;
match reply {
DaemonReply::Result(Ok(())) => Ok(()),
DaemonReply::Result(Err(e)) => bail!("{e}"),
other => bail!("unexpected WritePinnedMemory reply: {other:?}"),
}
}

/// Register a pool on a remote machine via the daemon (the daemon
/// resolves the machine through the coordinator and mirrors the
/// pool there with a synchronous confirmation).
#[allow(clippy::too_many_arguments)]
pub fn register_cross_machine_pool(
&mut self,
shared_memory_id: String,
shmem_name: String,
size: usize,
dtype: String,
shape: Vec<i64>,
device: String,
machine_id: String,
) -> eyre::Result<(Result<(), String>, bool)> {
let request = DaemonRequest::RegisterCrossMachinePool {
shared_memory_id,
shmem_name,
size,
dtype,
shape,
device,
machine_id,
};
let reply = self
.channel
.request(&Timestamped {
inner: request,
timestamp: self.clock.new_timestamp(),
})
.wrap_err("failed to send RegisterCrossMachinePool request to dora-daemon")?;
match reply {
DaemonReply::CrossMachinePoolRegistered { result, direct } => Ok((result, direct)),
other => bail!("unexpected RegisterCrossMachinePool reply: {other:?}"),
}
}
}
41 changes: 41 additions & 0 deletions apis/rust/node/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,47 @@ impl DoraNode {
pub fn free_pinned_memory(&mut self, shared_memory_id: String) -> Result<(), eyre::Error> {
self.control_channel.free_pinned_memory(shared_memory_id)
}

/// Write tensor bytes to a pinned memory pool via the daemon. The
/// daemon forwards the payload to remote daemons so the mirror pool
/// is updated in place.
pub fn write_pinned_memory(
&mut self,
shared_memory_id: String,
tensor_data: Vec<u8>,
size: usize,
) -> Result<(), eyre::Error> {
self.control_channel
.write_pinned_memory(shared_memory_id, tensor_data, size)
}

/// Register a memory pool on a remote machine via the daemon. The
/// daemon resolves the machine through the coordinator and mirrors
/// the pool there with a synchronous confirmation, returning
/// `Ok(Ok(()))` on success or `Ok(Err(msg))` when the mirror failed
/// (unresolved machine, remote pool creation failure, or ack
/// timeout).
#[allow(clippy::too_many_arguments)]
pub fn register_cross_machine_pool(
&mut self,
shared_memory_id: String,
shmem_name: String,
size: usize,
dtype: String,
shape: Vec<i64>,
device: String,
machine_id: String,
) -> Result<(Result<(), String>, bool), eyre::Error> {
self.control_channel.register_cross_machine_pool(
shared_memory_id,
shmem_name,
size,
dtype,
shape,
device,
machine_id,
)
}
}

/// Builder for initializing a node with custom connection parameters.
Expand Down
5 changes: 5 additions & 0 deletions binaries/cli/src/command/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,11 @@ fn run_record_proxy(args: Record) -> eyre::Result<()> {
node_id, output_id, ..
} => (node_id.to_string(), output_id.to_string()),
InterDaemonEvent::OutputClosed { .. } => continue,
InterDaemonEvent::MemoryPoolWrite { .. } => continue,
InterDaemonEvent::RegisterPool { .. }
| InterDaemonEvent::RegisterPoolAck { .. }
| InterDaemonEvent::MemoryPoolWriteAck { .. }
| InterDaemonEvent::FreePool { .. } => continue,
};

let now_nanos = SystemTime::now()
Expand Down
5 changes: 5 additions & 0 deletions binaries/cli/src/command/topic/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ fn inspect(
} => {
eprintln!("Output {node_id}/{output_id} closed");
}
InterDaemonEvent::MemoryPoolWrite { .. } => {}
InterDaemonEvent::RegisterPool { .. }
| InterDaemonEvent::RegisterPoolAck { .. }
| InterDaemonEvent::MemoryPoolWriteAck { .. }
| InterDaemonEvent::FreePool { .. } => {}
}
}

Expand Down
5 changes: 5 additions & 0 deletions binaries/cli/src/command/topic/hz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ fn run_hz(
}
}
InterDaemonEvent::OutputClosed { .. } => {}
InterDaemonEvent::MemoryPoolWrite { .. } => {}
InterDaemonEvent::RegisterPool { .. }
| InterDaemonEvent::RegisterPoolAck { .. }
| InterDaemonEvent::MemoryPoolWriteAck { .. }
| InterDaemonEvent::FreePool { .. } => {}
}
}
});
Expand Down
5 changes: 5 additions & 0 deletions binaries/cli/src/command/topic/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ fn info(
stats_clone.record(data_size, data_type, Instant::now());
}
InterDaemonEvent::OutputClosed { .. } => break,
InterDaemonEvent::MemoryPoolWrite { .. } => {}
InterDaemonEvent::RegisterPool { .. }
| InterDaemonEvent::RegisterPoolAck { .. }
| InterDaemonEvent::MemoryPoolWriteAck { .. }
| InterDaemonEvent::FreePool { .. } => {}
}
}
Ok(Err(_)) => continue,
Expand Down
18 changes: 18 additions & 0 deletions binaries/coordinator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,20 @@ async fn start_with_events(
#[cfg(feature = "metrics")]
let otel_metrics = otel_metrics::new_shared();

// DaemonId -> WS peer address, shared with the WS server so the
// ResolveMachine reply can carry the target daemon's direct-TCP data
// listener address.
let daemon_peer_addrs: Arc<
std::sync::RwLock<std::collections::HashMap<String, std::net::SocketAddr>>,
> = Arc::new(std::sync::RwLock::new(std::collections::HashMap::new()));
let (port, ws_shutdown, ws_future) = ws_server::serve(
bind,
ws_event_tx.clone(),
clock.clone(),
auth_token,
artifact_store,
store.clone(),
daemon_peer_addrs.clone(),
)
.await
.wrap_err("failed to start WS server")?;
Expand All @@ -274,6 +282,7 @@ async fn start_with_events(
clock,
store,
span_store,
daemon_peer_addrs,
#[cfg(feature = "metrics")]
otel_metrics,
)
Expand All @@ -299,6 +308,9 @@ async fn start_inner(
clock: Arc<HLC>,
store: Arc<dyn CoordinatorStore>,
span_store: SpanStore,
daemon_peer_addrs: Arc<
std::sync::RwLock<std::collections::HashMap<String, std::net::SocketAddr>>,
>,
#[cfg(feature = "metrics")] otel_metrics: otel_metrics::SharedMetrics,
) -> eyre::Result<()> {
let daemon_heartbeat_interval =
Expand Down Expand Up @@ -427,6 +439,12 @@ async fn start_inner(
match version_check_result.map_err(|e| eyre!(e)).and(send_result) {
Ok(()) => {
let _ = daemon_id_tx.send(daemon_id.clone());
if let Some(peer_addr) = connection.peer_addr {
daemon_peer_addrs
.write()
.unwrap_or_else(|e| e.into_inner())
.insert(daemon_id.to_string(), peer_addr);
}
daemon_connections.add(daemon_id.clone(), connection);
if let Err(e) =
store.register_daemon(dora_coordinator_store::DaemonInfo {
Expand Down
5 changes: 5 additions & 0 deletions binaries/coordinator/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ pub(crate) struct DaemonConnection {
pub(crate) sender: mpsc::Sender<String>,
/// Shared with the ws_daemon handler task to resolve correlation-based replies.
pub(crate) pending_replies: Arc<Mutex<HashMap<Uuid, oneshot::Sender<String>>>>,
/// The daemon's WS peer address as seen by the coordinator (set at
/// registration). Lets other daemons reach this daemon's direct-TCP
/// memory-pool data listener.
pub(crate) peer_addr: Option<std::net::SocketAddr>,
pub(crate) last_heartbeat: Instant,
pub(crate) labels: BTreeMap<String, String>,
/// Latest fault tolerance stats from this daemon (updated on each heartbeat).
Expand Down Expand Up @@ -131,6 +135,7 @@ impl DaemonConnection {
Self {
sender,
pending_replies,
peer_addr: None,
last_heartbeat: Instant::now(),
labels,
ft_stats: None,
Expand Down
70 changes: 68 additions & 2 deletions binaries/coordinator/src/ws_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ use crate::{
state::DaemonConnection,
};
use axum::extract::ws::{Message, WebSocket};
use dora_coordinator_store::CoordinatorStore;
use dora_core::uhlc::HLC;
use dora_message::{
common::DaemonId,
daemon_to_coordinator::{CoordinatorRequest, DaemonEvent},
coordinator_to_daemon::ResolveMachineReply,
daemon_to_coordinator::{CoordinatorRequest, DaemonEvent, Timestamped},
ws_protocol::WsResponse,
};
use futures::{SinkExt, StreamExt};
Expand All @@ -22,6 +24,11 @@ pub(crate) async fn handle_daemon_ws(
socket: WebSocket,
event_tx: mpsc::Sender<Event>,
clock: Arc<HLC>,
store: Arc<dyn CoordinatorStore>,
peer_addr: std::net::SocketAddr,
daemon_peer_addrs: Arc<
std::sync::RwLock<std::collections::HashMap<String, std::net::SocketAddr>>,
>,
) {
let (mut ws_tx, mut ws_rx) = socket.split();

Expand Down Expand Up @@ -74,9 +81,14 @@ pub(crate) async fn handle_daemon_ws(
&clock,
&cmd_tx,
&pending_replies,
&store,
&mut tracked_daemon_id,
&mut tracked_connection_id,
).await {
peer_addr,
daemon_peer_addrs.clone(),
)
.await
{
break;
}
} else {
Expand Down Expand Up @@ -112,20 +124,29 @@ pub(crate) async fn handle_daemon_ws(
/// instead of going through the `serde_json::Value` used for routing.
#[derive(serde::Deserialize)]
struct DaemonWsRequestRaw {
/// Request id from the daemon envelope — echoed back in replies so
/// the daemon can route the reply to its pending caller.
id: Uuid,
params: dora_message::daemon_to_coordinator::Timestamped<
dora_message::daemon_to_coordinator::CoordinatorRequest,
>,
}

/// Handle a daemon request (event or register). Returns false if the event channel closed.
#[allow(clippy::too_many_arguments)]
async fn handle_daemon_request(
raw_text: &str,
event_tx: &mpsc::Sender<Event>,
clock: &HLC,
cmd_tx: &mpsc::Sender<String>,
pending_replies: &Arc<Mutex<HashMap<Uuid, oneshot::Sender<String>>>>,
store: &Arc<dyn CoordinatorStore>,
tracked_daemon_id: &mut Option<DaemonId>,
tracked_connection_id: &mut Option<Uuid>,
peer_addr: std::net::SocketAddr,
daemon_peer_addrs: Arc<
std::sync::RwLock<std::collections::HashMap<String, std::net::SocketAddr>>,
>,
) -> bool {
let parsed: DaemonWsRequestRaw = match serde_json::from_str(raw_text) {
Ok(m) => m,
Expand All @@ -135,6 +156,7 @@ async fn handle_daemon_request(
}
};
let message = parsed.params;
let request_id = parsed.id;

if let Err(err) = clock.update_with_timestamp(&message.timestamp) {
tracing::warn!("failed to update coordinator clock: {err}");
Expand Down Expand Up @@ -165,6 +187,7 @@ async fn handle_daemon_request(
let mut connection =
DaemonConnection::new(cmd_tx.clone(), pending_replies.clone(), labels.clone());
connection.supports_hub_sources = supports_hub_sources;
connection.peer_addr = Some(peer_addr);
// Capture the connection_id before moving `connection` into the event.
let connection_id = connection.connection_id;
let (daemon_id_tx, daemon_id_rx) = oneshot::channel();
Expand Down Expand Up @@ -209,6 +232,49 @@ async fn handle_daemon_request(
true
}
}
CoordinatorRequest::ResolveMachine { machine_id } => {
// Resolve the machine id against the registered-daemon store;
// unknown machines (or store errors) resolve to `found: false`.
// Also report the target daemon's WS peer address so the
// requesting daemon can reach its direct-TCP data listener.
let (found, address) = match store.get_daemon_by_machine(&machine_id) {
Ok(Some(d)) => (
true,
daemon_peer_addrs
.read()
.unwrap_or_else(|e| e.into_inner())
.get(&d.to_string())
.copied(),
),
Ok(None) => (false, None),
Err(e) => {
tracing::warn!("failed to resolve machine `{machine_id}`: {e}");
(false, None)
}
};
// Reply over the same WS envelope the Register flow uses
// (`{"id", "method": "daemon_event", "params": <Timestamped<...>>}`),
// mirroring `DaemonConnection::send`.
let reply = Timestamped {
inner: ResolveMachineReply::ResolveMachineResult { found, address },
timestamp: clock.new_timestamp(),
};
let params = match serde_json::to_string(&reply) {
Ok(params) => params,
Err(err) => {
tracing::warn!("failed to serialize ResolveMachine reply: {err}");
return true;
}
};
// Echo the request id so the daemon can route this reply to
// its pending caller (COORDINATOR_PENDING).
let json =
format!(r#"{{"id":"{request_id}","method":"daemon_event","params":{params}}}"#);
if cmd_tx.send(json).await.is_err() {
return false;
}
true
}
}
}

Expand Down
Loading