hive-c0re: keep agent and manager listeners alive across accept errors
Both accept loops returned on the first accept() error. The AgentSocket stayed in Coordinator.agents, so mcp_sockets::sync_on_start skipped the agent, and only a Start node or a hive-c0re restart bound it again. The unit sets no LimitNOFILE, so a single EMFILE at the 1024-fd soft limit cut the agent off from send/recv/ack with one warn line as the only trace. Both loops now share accept_until_fatal. Connection errors (ECONNABORTED/ECONNRESET/ECONNREFUSED) retry at once, any other error retries after 1 s, following axum's serve loop that the dashboard already runs. Errors that leave the listening fd unusable (EBADF, EFAULT, EINVAL, ENOTSOCK, EOPNOTSUPP) log at error and exit the process: nothing re-binds a listener while hive-c0re runs, the manager listener has no re-bind path at all, and the unit's Restart=on-failure restart runs start_manager and sync_on_start, which re-bind every socket. mcp_sockets.rs now states that invariant instead of asserting that a listener can only disappear on restart. LimitNOFILE is left unset: per-agent fd use is a listener plus a Recv long-poll plus short-lived requests, and a higher limit would raise the memory ceiling of the per-line bound (bound x open connections). Closes #4721
This commit is contained in:
parent
65a1f8d902
commit
386741d38f
2 changed files with 110 additions and 36 deletions
|
|
@ -10,9 +10,11 @@
|
|||
//! - `run_reconcile` calls `register_agent` immediately after `start_with_fallback`.
|
||||
//! - `kill`/`destroy` paths call `unregister_agent`.
|
||||
//!
|
||||
//! No recurring poll is needed because c0re owns the listener lifecycle —
|
||||
//! a listener can only disappear when c0re itself restarts, which is exactly
|
||||
//! the case `sync_on_start` covers.
|
||||
//! No recurring poll is needed because c0re owns the listener lifecycle. An
|
||||
//! accept loop retries every error except one that leaves its fd unusable,
|
||||
//! and on that one hive-c0re exits (`socket_server::exit_on_dead_listener`),
|
||||
//! so a listener only disappears across a restart — exactly the case
|
||||
//! `sync_on_start` covers.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue