A shared status, kept by the worker and the walk and read by the report under its own leaf lock, holds the workspaces whose key was refused, when an outage of Honcho began, and when brokerd stopped answering. The report adds a line for each while it lasts, and is unchanged when all is well. The runbook's Honcho entries and broker-state-unavailable now say what sync shows. Tuning and Wake move to honcho/wake.rs (re-exported from worker) to keep worker.rs under 500 lines. honcho_sync.rs's serve test now allows the outage line: the write wakes the worker, which finds Honcho unreachable. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
99 lines
3.5 KiB
Rust
99 lines
3.5 KiB
Rust
//! `memoryd`'s Honcho side at start (M5c spec, sections 5 and 10): the ledger read through, the
|
|
//! sessions that wait again, the clients with their keys, and the worker's thread.
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use bxcore::{SessionId, Timestamp};
|
|
|
|
use crate::config::Config;
|
|
use crate::honcho::client::{Clients, Timeouts};
|
|
use crate::honcho::config::HonchoConfig;
|
|
use crate::honcho::ledger::{Ledger, Record};
|
|
use crate::honcho::mirror::Mirror;
|
|
use crate::honcho::state;
|
|
use crate::honcho::turns::{LEDGER, TurnSync};
|
|
use crate::honcho::worker::{AskBox, Tuning, Wake, Worker};
|
|
use crate::serve::{Log, StartError};
|
|
|
|
/// With `[honcho]`, at start: the ledger read through, the sessions that wait again, and the
|
|
/// clients with their keys read. Nothing is bound or started yet.
|
|
pub struct Opened {
|
|
pub sync: Arc<Mutex<TurnSync>>,
|
|
clients: Clients,
|
|
agent: String,
|
|
owner: String,
|
|
}
|
|
|
|
impl Opened {
|
|
/// The first time: sync begins now. The `Began` line is written and synced once `memory/`
|
|
/// exists and before any socket is bound, so every turn reported later is after it.
|
|
pub fn begin(&self) -> Result<(), StartError> {
|
|
let sync = self.sync.lock().unwrap_or_else(|p| p.into_inner());
|
|
let mut ledger = sync.ledger();
|
|
if ledger.began().is_none() {
|
|
let began = Record::Began {
|
|
time: Timestamp::now(),
|
|
};
|
|
ledger.append(began).map_err(StartError::Ledger)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// The memory writes' side of the ledger (task 12).
|
|
pub fn mirror(&self) -> Mirror {
|
|
let (ledger, status) = {
|
|
let sync = self.sync.lock().unwrap_or_else(|p| p.into_inner());
|
|
(sync.shared_ledger(), sync.shared_status())
|
|
};
|
|
Mirror::new(ledger, &self.agent, &self.owner).with_status(status)
|
|
}
|
|
}
|
|
|
|
/// Open the ledger (a cut-off last line is logged), resume the waiting sessions, and build the
|
|
/// clients (their key files' warnings are logged). A key that cannot be read is `Secret`.
|
|
pub fn open(config: &Config, honcho: &HonchoConfig, log: &Log) -> Result<Opened, StartError> {
|
|
let path = config.memory_dir().join(LEDGER);
|
|
let ledger = Ledger::open(&path).map_err(StartError::Ledger)?;
|
|
if ledger.repaired() {
|
|
(log)(&format!(
|
|
"memoryd: {}: a last line cut off by a crash was dropped",
|
|
path.display()
|
|
));
|
|
}
|
|
let mut sync = TurnSync::new(ledger, &honcho.agent, &config.sessions_dir());
|
|
sync.resume();
|
|
let env = |name: &str| std::env::var_os(name);
|
|
let (clients, warnings) =
|
|
Clients::new(honcho, &env, Timeouts::WRITES).map_err(StartError::Secret)?;
|
|
for warning in warnings {
|
|
(log)(&warning);
|
|
}
|
|
Ok(Opened {
|
|
sync: Arc::new(Mutex::new(sync)),
|
|
clients,
|
|
agent: honcho.agent.clone(),
|
|
owner: honcho.owner.clone(),
|
|
})
|
|
}
|
|
|
|
/// Start the worker's thread, asking `brokerd` on `config`'s state socket.
|
|
pub fn spawn(opened: Opened, config: &Config, wake: Arc<Wake>, log: Log) -> Result<(), String> {
|
|
let socket = config.state_socket();
|
|
let ask: AskBox =
|
|
Box::new(move |session: &SessionId| state::ask(&socket, session, state::WAIT));
|
|
let worker = Worker::new(
|
|
opened.sync,
|
|
opened.clients,
|
|
wake,
|
|
ask,
|
|
log,
|
|
Tuning::DEFAULT,
|
|
&opened.agent,
|
|
);
|
|
std::thread::Builder::new()
|
|
.name("honcho".to_string())
|
|
.spawn(move || worker.run())
|
|
.map(|_| ())
|
|
.map_err(|e| format!("cannot start the Honcho worker: {e}"))
|
|
}
|