review: loopd prints every startup notice before it binds; tests wait for "serving on"

The serve tests waited for the socket file, then killed `loopd` and read its stderr, but the
socket is bound before its mode is set and before "serving on" and the broker notice are printed,
so a kill in between lost those lines (`pointers` failed once under load in M5c-1 task 15). The
broker notice now comes before the bind, so "serving on" is the last startup line, and the tests
wait for it (`tests/support/serving.rs`).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-28 14:26:37 -07:00
co-authored by Claude Opus 5.5
parent 45be83b891
commit e83b53b8b6
4 changed files with 89 additions and 42 deletions
+12 -10
View File
@@ -102,6 +102,18 @@ fn run_serve(path: &Path) -> ExitCode {
return ExitCode::from(1);
}
// Every startup notice comes before the socket is bound, so "serving on" is the last line
// before loopd serves: a supervisor or test that waits for it has seen all the others.
let port: Box<dyn ToolPort> = match &cfg.broker.socket {
Some(socket) => Box::new(BrokerPort::new(
socket.clone(),
Duration::from_millis(cfg.broker.timeout_ms),
)),
None => {
eprintln!("{}", not_configured_line());
Box::new(NoBroker)
}
};
if let Some(parent) = socket.parent()
&& let Err(e) = std::fs::create_dir_all(parent)
{
@@ -121,16 +133,6 @@ fn run_serve(path: &Path) -> ExitCode {
}
eprintln!("loopd: serving on {}", socket.display());
let port: Box<dyn ToolPort> = match &cfg.broker.socket {
Some(socket) => Box::new(BrokerPort::new(
socket.clone(),
Duration::from_millis(cfg.broker.timeout_ms),
)),
None => {
eprintln!("{}", not_configured_line());
Box::new(NoBroker)
}
};
let memory = Box::new(MemoryPort::new(cfg.memory_socket(), MEMORY_WAIT));
let ctx = Arc::new(Context::new(cfg, client, port, Registry::m5a(), memory));
if let Err(e) = channel::serve(listener, ctx) {