Exclude component compilation from command deadlines
This commit is contained in:
+73
-68
@@ -47,6 +47,7 @@ mod bindings {
|
||||
}
|
||||
use bindings::sausage::process::host::{Host, HostChild, Request, Stdio};
|
||||
mod cache;
|
||||
mod deadline;
|
||||
mod http;
|
||||
pub use http::Router;
|
||||
pub mod net;
|
||||
@@ -83,6 +84,7 @@ struct Entry {
|
||||
command: u32,
|
||||
group: u32,
|
||||
cancelled: Arc<AtomicBool>,
|
||||
deadline: Option<Arc<deadline::Deadline>>,
|
||||
tag: sausage_vfs::journal::Tag,
|
||||
abort: AbortHandle,
|
||||
}
|
||||
@@ -329,16 +331,17 @@ impl Runtime {
|
||||
conversations: Vec<String>,
|
||||
inherited_io: Option<Io>,
|
||||
tool_call: Option<String>,
|
||||
deadline: Option<Arc<deadline::Deadline>>,
|
||||
) -> anyhow::Result<Started> {
|
||||
anyhow::ensure!(!request.argv.is_empty(), "empty argv");
|
||||
let cancelled = if parent == 0 {
|
||||
Arc::new(AtomicBool::new(false))
|
||||
let (cancelled, deadline) = if parent == 0 {
|
||||
(Arc::new(AtomicBool::new(false)), deadline)
|
||||
} else {
|
||||
self.entries
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&parent)
|
||||
.map(|entry| entry.cancelled.clone())
|
||||
.map(|entry| (entry.cancelled.clone(), entry.deadline.clone()))
|
||||
.ok_or_else(|| anyhow::anyhow!("parent exited"))?
|
||||
};
|
||||
if !request.env.iter().any(|(k, _)| k == "PATH") {
|
||||
@@ -366,7 +369,9 @@ impl Runtime {
|
||||
let bytes = file
|
||||
.read(0, usize::try_from(file.stat().await?.size)?)
|
||||
.await?;
|
||||
let compilation = deadline.as_ref().map(|deadline| deadline.pause());
|
||||
let pre = self.compiler.get(bytes.clone()).await?;
|
||||
drop(compilation);
|
||||
self.cache.lock().unwrap().insert(bytes);
|
||||
let pid = self.next.fetch_add(1, Ordering::Relaxed);
|
||||
let tag = if parent == 0 {
|
||||
@@ -528,6 +533,7 @@ impl Runtime {
|
||||
command,
|
||||
group,
|
||||
cancelled: cancelled.clone(),
|
||||
deadline,
|
||||
tag,
|
||||
abort: task.abort_handle(),
|
||||
},
|
||||
@@ -583,6 +589,7 @@ impl Host for State {
|
||||
self.conversations.clone(),
|
||||
Some(self.stdio.clone()),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -707,79 +714,77 @@ impl Exec for Arc<Runtime> {
|
||||
options: Options,
|
||||
output: &mut (dyn for<'chunk> FnMut(Stream, &'chunk [u8]) + Send),
|
||||
) -> anyhow::Result<i32> {
|
||||
let deadline = options
|
||||
.timeout
|
||||
.map(|duration| tokio::time::Instant::now() + duration);
|
||||
let argv = match command {
|
||||
Command::Shell(script) => vec![
|
||||
"/bin/sh".into(),
|
||||
"--noprofile".into(),
|
||||
"--norc".into(),
|
||||
"-c".into(),
|
||||
script,
|
||||
],
|
||||
Command::Argv(argv) => argv,
|
||||
};
|
||||
let env = options.env;
|
||||
let start = self.start(
|
||||
Request {
|
||||
program: argv.first().cloned().unwrap_or_default(),
|
||||
argv,
|
||||
env,
|
||||
cwd: options.cwd,
|
||||
group: None,
|
||||
stdin: Stdio::Pipe,
|
||||
stdout: Stdio::Pipe,
|
||||
stderr: Stdio::Pipe,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
options.conversations,
|
||||
None,
|
||||
options.tool_call,
|
||||
);
|
||||
let mut child = if let Some(deadline) = deadline {
|
||||
tokio::time::timeout_at(deadline, start)
|
||||
.await
|
||||
.map_err(|_| anyhow::anyhow!("command timed out"))??
|
||||
} else {
|
||||
start.await?
|
||||
};
|
||||
let _guard = GroupGuard {
|
||||
runtime: self.clone(),
|
||||
group: child.pid,
|
||||
};
|
||||
drop(child.input);
|
||||
let mut stdout = child.output.take().unwrap();
|
||||
let mut stderr = child.error.take().unwrap();
|
||||
let deadline = options.timeout.map(deadline::Deadline::new);
|
||||
let run = async {
|
||||
let (mut out_open, mut err_open) = (true, true);
|
||||
let (mut out, mut err) = ([0; 8192], [0; 8192]);
|
||||
while out_open || err_open {
|
||||
tokio::select! {
|
||||
n = stdout.read(&mut out), if out_open => { let n = n?; out_open = n != 0; if n != 0 { output(Stream::Stdout, &out[..n]); } }
|
||||
n = stderr.read(&mut err), if err_open => { let n = n?; err_open = n != 0; if n != 0 { output(Stream::Stderr, &err[..n]); } }
|
||||
let argv = match command {
|
||||
Command::Shell(script) => vec![
|
||||
"/bin/sh".into(),
|
||||
"--noprofile".into(),
|
||||
"--norc".into(),
|
||||
"-c".into(),
|
||||
script,
|
||||
],
|
||||
Command::Argv(argv) => argv,
|
||||
};
|
||||
let env = options.env;
|
||||
let mut child = self
|
||||
.start(
|
||||
Request {
|
||||
program: argv.first().cloned().unwrap_or_default(),
|
||||
argv,
|
||||
env,
|
||||
cwd: options.cwd,
|
||||
group: None,
|
||||
stdin: Stdio::Pipe,
|
||||
stdout: Stdio::Pipe,
|
||||
stderr: Stdio::Pipe,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
options.conversations,
|
||||
None,
|
||||
options.tool_call,
|
||||
deadline.clone(),
|
||||
)
|
||||
.await?;
|
||||
let _guard = GroupGuard {
|
||||
runtime: self.clone(),
|
||||
group: child.pid,
|
||||
};
|
||||
drop(child.input);
|
||||
let mut stdout = child.output.take().unwrap();
|
||||
let mut stderr = child.error.take().unwrap();
|
||||
let run = async {
|
||||
let (mut out_open, mut err_open) = (true, true);
|
||||
let (mut out, mut err) = ([0; 8192], [0; 8192]);
|
||||
while out_open || err_open {
|
||||
tokio::select! {
|
||||
n = stdout.read(&mut out), if out_open => { let n = n?; out_open = n != 0; if n != 0 { output(Stream::Stdout, &out[..n]); } }
|
||||
n = stderr.read(&mut err), if err_open => { let n = n?; err_open = n != 0; if n != 0 { output(Stream::Stderr, &err[..n]); } }
|
||||
}
|
||||
}
|
||||
}
|
||||
loop {
|
||||
if let Some(code) = *child.code.borrow_and_update() {
|
||||
return Ok(code);
|
||||
loop {
|
||||
if let Some(code) = *child.code.borrow_and_update() {
|
||||
return Ok(code);
|
||||
}
|
||||
child.code.changed().await?;
|
||||
}
|
||||
child.code.changed().await?;
|
||||
};
|
||||
let result = run.await;
|
||||
if let Some(journal) = self.world.root.journal() {
|
||||
journal.retain().await?;
|
||||
}
|
||||
result
|
||||
};
|
||||
let result = if let Some(deadline) = deadline {
|
||||
tokio::time::timeout_at(deadline, run)
|
||||
.await
|
||||
.map_err(|_| anyhow::anyhow!("command timed out"))?
|
||||
if let Some(deadline) = &deadline {
|
||||
tokio::select! {
|
||||
result = run => result,
|
||||
_ = deadline.expired() => anyhow::bail!("command timed out"),
|
||||
}
|
||||
} else {
|
||||
run.await
|
||||
};
|
||||
if let Some(journal) = self.world.root.journal() {
|
||||
journal.retain().await?;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
/// Construct the harness's shared executor over the same open world.
|
||||
|
||||
Reference in New Issue
Block a user