brokerd: start pipe threads safely and collect output within a grace period
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::config::Runner;
|
||||
use crate::pipes::Io;
|
||||
use crate::pipes::{GRACE, Io};
|
||||
use crate::podman;
|
||||
use crate::runner::{RunError, RunOutput, RunSpec, Runtime};
|
||||
|
||||
@@ -20,6 +20,7 @@ pub const COULD_NOT_RUN: &str = "the tool could not run";
|
||||
pub const CANNOT_START: &str = "the tool runner could not start the container";
|
||||
pub const KILLED: &str = "the tool was stopped: it ran out of memory or was killed";
|
||||
pub const TIMED_OUT: &str = "the tool ran past its time limit";
|
||||
pub const OUTPUT_OPEN: &str = "the tool left its output open";
|
||||
pub const UNEXPECTED: &str = "the tool failed with an unexpected status";
|
||||
/// How often a running container is checked.
|
||||
pub const POLL: Duration = Duration::from_millis(50);
|
||||
@@ -144,10 +145,29 @@ impl Podman {
|
||||
};
|
||||
let started = Instant::now();
|
||||
let cap = usize::try_from(self.runner.output_cap).unwrap_or(usize::MAX);
|
||||
let io = Io::start(&mut child, input, cap);
|
||||
let io = match Io::start(&mut child, input, cap, STDERR_KEPT) {
|
||||
Ok(io) => io,
|
||||
Err(e) => {
|
||||
// The container may be running: stop it before answering.
|
||||
self.podman(&["kill", name]);
|
||||
self.podman(&["rm", "-f", name]);
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
(self.log)(&format!(
|
||||
"brokerd: cannot start a thread for {name}: {e}\n{RUNBOOK}"
|
||||
));
|
||||
return Err(RunError::Unavailable(CANNOT_START.to_string()));
|
||||
}
|
||||
};
|
||||
let status = self.wait(&mut child, name, started, limit);
|
||||
let (out, truncated, err) = io.finish();
|
||||
self.answer(name, status, out, truncated, &err)
|
||||
let done = io.finish(GRACE);
|
||||
if done.open && status.is_some() {
|
||||
(self.log)(&format!(
|
||||
"brokerd: {name} ended but something still holds its output; it was abandoned"
|
||||
));
|
||||
return Err(RunError::Failed(OUTPUT_OPEN.to_string()));
|
||||
}
|
||||
self.answer(name, status, done.out, done.truncated, &done.err)
|
||||
}
|
||||
|
||||
/// Step 3: spawn `podman` with `args` and all three standard streams piped. On failure, log
|
||||
|
||||
Reference in New Issue
Block a user