brokerd: state.sock answers memoryd's question about a session's state

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
2026-09-28 11:05:42 -07:00
co-authored by ornith-1.5-35b-a3b
parent 5199bd7149
commit 9b4e9807b2
12 changed files with 758 additions and 14 deletions
+16 -6
View File
@@ -1,4 +1,4 @@
//! `brokerd serve`: bring the broker up, listen on both sockets, and keep it running.
//! `brokerd serve`: bring the broker up, listen on its three sockets, and keep it running.
use std::fs::{DirBuilder, Permissions};
use std::io;
@@ -16,6 +16,7 @@ use crate::config::Config;
use crate::ledger::Ledger;
use crate::runner::Runtime;
use crate::state::StateStore;
use crate::state_socket;
use bxcore::{ChainFailure, Timestamp};
/// A failure while `brokerd serve` is starting up.
@@ -48,16 +49,17 @@ impl std::error::Error for ServeError {
}
}
/// The result of `start`: a running broker with both sockets open.
/// The result of `start`: a running broker with its three sockets open.
pub struct Started {
pub broker: Arc<Broker>,
pub recovered: bool,
pub accepted: Option<ChainFailure>,
tools: UnixListener,
admin: UnixListener,
state: UnixListener,
}
/// Start the broker: open the audit chain, bind both sockets, and build the ledger and broker.
/// Start the broker: open the audit chain, bind the three sockets, and build the ledger and broker.
pub fn start(
cfg: Config,
accept_break: bool,
@@ -67,7 +69,9 @@ pub fn start(
// The audit lock comes first: if the chain will not open, no directory or socket is made.
let opened = Writer::open(&cfg.audit_dir(), accept_break).map_err(ServeError::Audit)?;
// Both sockets, in the order the task gives.
// The three sockets. `state.sock` comes first: whoever waits for the tool and admin sockets
// then finds it bound too.
let state = listen(&cfg.state_socket())?;
let tools = listen(&cfg.broker_socket())?;
let admin = listen(&cfg.admin_socket())?;
@@ -93,6 +97,7 @@ pub fn start(
accepted: opened.accepted.map(|b| *b),
tools,
admin,
state,
})
}
@@ -156,6 +161,7 @@ fn listen(socket: &Path) -> Result<UnixListener, ServeError> {
enum Which {
Tools,
Admin,
State,
}
/// Run the broker: start the expiry thread, one accept thread per socket, then wait for the
@@ -166,6 +172,7 @@ impl Started {
broker,
tools,
admin,
state,
..
} = self;
@@ -187,7 +194,8 @@ impl Started {
let (tx, rx) = mpsc::channel::<io::Error>();
accept_loop(tools, Arc::clone(&broker), tx.clone(), Which::Tools)?;
accept_loop(admin, Arc::clone(&broker), tx, Which::Admin)?;
accept_loop(admin, Arc::clone(&broker), tx.clone(), Which::Admin)?;
accept_loop(state, Arc::clone(&broker), tx, Which::State)?;
// The first listener error stops the daemon.
match rx.recv() {
@@ -200,7 +208,7 @@ impl Started {
/// Accept streams from one listener forever, starting a handler thread per stream. When the
/// system is out of file descriptors or memory, the listener pauses and tries again instead of
/// stopping: otherwise a peer holding many idle connections could stop the daemon, and the other
/// socket with it. Any other error stops the daemon through `tx`.
/// sockets with it. Any other error stops the daemon through `tx`.
fn accept_loop(
listener: UnixListener,
broker: Arc<Broker>,
@@ -210,6 +218,7 @@ fn accept_loop(
let name = match which {
Which::Tools => "accept-broker",
Which::Admin => "accept-admin",
Which::State => "accept-state",
};
std::thread::Builder::new()
.name(name.to_string())
@@ -248,6 +257,7 @@ fn serve_one(stream: UnixStream, broker: &Arc<Broker>, which: Which) {
let started = std::thread::Builder::new().spawn(move || match which {
Which::Tools => broker::handle(stream, &for_thread),
Which::Admin => admin::handle(stream, &for_thread),
Which::State => state_socket::handle(stream, &for_thread),
});
if let Err(e) = started {
broker.log(&format!(