memoryd: the Honcho worker sends decided turns, waits out outages, retries undecided turns
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
//! A Honcho worker for tests, stepped by hand: a home with session logs and a ledger, the fake
|
||||
//! Honcho, `brokerd` as a closure whose answer the test sets, and the log lines collected. Do not
|
||||
//! edit.
|
||||
|
||||
#![allow(dead_code)] // each test file uses a different part of this module
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use bxcore::{LogRecord, SessionStateReply, Timestamp};
|
||||
use memoryd::honcho::client::{Clients, Timeouts};
|
||||
use memoryd::honcho::config::HonchoConfig;
|
||||
use memoryd::honcho::ledger::{Ledger, Record};
|
||||
use memoryd::honcho::turns::{LEDGER, TurnSync};
|
||||
use memoryd::honcho::worker::{Tuning, Wake, Worker};
|
||||
use memoryd::serve::Log;
|
||||
|
||||
use crate::honcho::FakeHoncho;
|
||||
use crate::tmp::TempDir;
|
||||
use crate::turns::{clean, sid, write_turns};
|
||||
|
||||
pub const FAST: Tuning = Tuning {
|
||||
backoff: Duration::from_millis(1),
|
||||
backoff_max: Duration::from_millis(8),
|
||||
idle: Duration::from_millis(1),
|
||||
};
|
||||
|
||||
pub fn config(url: &str) -> HonchoConfig {
|
||||
HonchoConfig {
|
||||
url: url.to_string(),
|
||||
agent: "boxmaker0".to_string(),
|
||||
owner: "kyle".to_string(),
|
||||
trusted: "boxmaker0-trusted".to_string(),
|
||||
untrusted: "boxmaker0-untrusted".to_string(),
|
||||
fleet: "fleet".to_string(),
|
||||
read: Vec::new(),
|
||||
keys: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Home {
|
||||
pub sync: Arc<Mutex<TurnSync>>,
|
||||
/// What `brokerd` answers.
|
||||
pub answer: Arc<Mutex<Result<SessionStateReply, String>>>,
|
||||
pub lines: Arc<Mutex<Vec<String>>>,
|
||||
pub dir: TempDir,
|
||||
}
|
||||
|
||||
impl Home {
|
||||
pub fn new(tag: &str) -> Home {
|
||||
let dir = TempDir::new(tag);
|
||||
std::fs::create_dir_all(dir.path().join("memory")).unwrap();
|
||||
Home {
|
||||
sync: Arc::new(Mutex::new(TurnSync::new(
|
||||
Ledger::open(&dir.path().join("memory").join(LEDGER)).unwrap(),
|
||||
"boxmaker0",
|
||||
&dir.path().join("sessions"),
|
||||
))),
|
||||
answer: Arc::new(Mutex::new(Ok(clean()))),
|
||||
lines: Arc::new(Mutex::new(Vec::new())),
|
||||
dir,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ledger_path(&self) -> PathBuf {
|
||||
self.dir.path().join("memory").join(LEDGER)
|
||||
}
|
||||
|
||||
/// A new `TurnSync` over the ledger as it is on disk, resumed: what a restart makes.
|
||||
pub fn restart(&mut self) {
|
||||
let mut sync = TurnSync::new(
|
||||
Ledger::open(&self.ledger_path()).unwrap(),
|
||||
"boxmaker0",
|
||||
&self.dir.path().join("sessions"),
|
||||
);
|
||||
sync.resume();
|
||||
self.sync = Arc::new(Mutex::new(sync));
|
||||
}
|
||||
|
||||
pub fn log(&self, session: &str, turns: &[Vec<LogRecord>]) {
|
||||
write_turns(self.dir.path(), session, turns);
|
||||
}
|
||||
|
||||
/// `loopd` reports turn `turn` of `session`: decided now, with `answer`.
|
||||
pub fn report(&self, session: &str, turn: u64) {
|
||||
let answer = Arc::clone(&self.answer);
|
||||
let ask = move |_: &bxcore::SessionId| answer.lock().unwrap().clone();
|
||||
let lines = Arc::clone(&self.lines);
|
||||
let log = move |line: &str| lines.lock().unwrap().push(line.to_string());
|
||||
let now = Timestamp::parse("2026-09-28T10:00:00.000Z").unwrap();
|
||||
self.sync
|
||||
.lock()
|
||||
.unwrap()
|
||||
.updated(&sid(session), turn, &ask, now, &log);
|
||||
}
|
||||
|
||||
pub fn worker(&self, fake: &FakeHoncho, tuning: Tuning) -> Worker {
|
||||
let no_env = |_: &str| -> Option<OsString> { None };
|
||||
let timeouts = Timeouts {
|
||||
connect: Duration::from_secs(5),
|
||||
read: Duration::from_millis(300),
|
||||
};
|
||||
let (clients, _) = Clients::new(&config(&fake.url), &no_env, timeouts).unwrap();
|
||||
let answer = Arc::clone(&self.answer);
|
||||
let lines = Arc::clone(&self.lines);
|
||||
let log: Log = Arc::new(move |line: &str| lines.lock().unwrap().push(line.to_string()));
|
||||
Worker::new(
|
||||
Arc::clone(&self.sync),
|
||||
clients,
|
||||
Arc::new(Wake::default()),
|
||||
Box::new(move |_: &bxcore::SessionId| answer.lock().unwrap().clone()),
|
||||
log,
|
||||
tuning,
|
||||
"boxmaker0",
|
||||
)
|
||||
}
|
||||
|
||||
/// Every record of the ledger on disk, in order.
|
||||
pub fn records(&self) -> Vec<Record> {
|
||||
std::fs::read_to_string(self.ledger_path())
|
||||
.unwrap_or_default()
|
||||
.lines()
|
||||
.map(|l| serde_json::from_str(l).unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn lines(&self) -> Vec<String> {
|
||||
self.lines.lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user