Spike: fs/upgrade/bench examples, agent resumes interrupted turns, world lock, short trap reasons
This commit is contained in:
+5
-1
@@ -628,8 +628,12 @@ impl Supervisor {
|
||||
async fn start_instance(&mut self) {
|
||||
if self.component.is_none() {
|
||||
let path = self.world().version_dir(&self.id, self.version).join("actor.wasm");
|
||||
let t = Instant::now();
|
||||
match self.broker.runtime.load(&path) {
|
||||
Ok(c) => self.component = Some(c),
|
||||
Ok(c) => {
|
||||
self.broker.log(&self.id, &format!("compiled version {} in {} ms", self.version, t.elapsed().as_millis()));
|
||||
self.component = Some(c);
|
||||
}
|
||||
Err(e) => {
|
||||
self.broker.log(&self.id, &format!("cannot load version {}: {e:#}", self.version));
|
||||
self.state = "broken";
|
||||
|
||||
@@ -147,6 +147,11 @@ async fn run(dir: PathBuf) -> Result<()> {
|
||||
if !world.exists() {
|
||||
bail!("{} is not a Sausage world. Create one with: sausage init {}", dir.display(), dir.display());
|
||||
}
|
||||
// One host process per world.
|
||||
let lock = std::fs::File::create(world.root.join(".lock"))?;
|
||||
if lock.try_lock().is_err() {
|
||||
bail!("another sausage process runs {}", dir.display());
|
||||
}
|
||||
let runtime = runtime::Runtime::new()?;
|
||||
let broker = Broker::new(world.clone(), runtime)?;
|
||||
|
||||
@@ -165,6 +170,7 @@ async fn run(dir: PathBuf) -> Result<()> {
|
||||
console.run_input().await;
|
||||
println!("Stopping actors …");
|
||||
broker.shutdown_all().await;
|
||||
drop(lock);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+25
-1
@@ -176,6 +176,24 @@ impl Instance {
|
||||
}
|
||||
}
|
||||
|
||||
fn log_note(path: &Path, text: &str) {
|
||||
use std::io::Write;
|
||||
if let Ok(mut f) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
|
||||
let _ = writeln!(f, "[sausage] {text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The most useful line of a trap: the `wasm trap: ...` reason.
|
||||
fn short_trap(full: &str) -> String {
|
||||
let line = full
|
||||
.lines()
|
||||
.find_map(|l| l.find("wasm trap:").map(|i| l[i..].to_string()))
|
||||
.unwrap_or_else(|| full.lines().next().unwrap_or("trap").to_string());
|
||||
let mut line = line.trim().to_string();
|
||||
line.truncate(300);
|
||||
line
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
pub fn new() -> Result<Arc<Self>> {
|
||||
let mut config = Config::new();
|
||||
@@ -251,6 +269,7 @@ impl Runtime {
|
||||
|
||||
let rt = self.clone();
|
||||
let component = component.clone();
|
||||
let stderr_log = cfg.stderr_log.clone();
|
||||
let task = tokio::spawn(async move {
|
||||
let mut store = Store::new(&rt.engine, state);
|
||||
store.epoch_deadline_async_yield_and_update(1);
|
||||
@@ -265,7 +284,12 @@ impl Runtime {
|
||||
Err(e) => match e.downcast_ref::<I32Exit>() {
|
||||
Some(I32Exit(0)) => Exit::Clean,
|
||||
Some(I32Exit(c)) => Exit::Code(*c),
|
||||
None => Exit::Trap(format!("{e:#}")),
|
||||
None => {
|
||||
// Keep the full backtrace in the log, and a short reason in the status.
|
||||
let full = format!("{e:?}");
|
||||
log_note(&stderr_log, &format!("trap details:\n{full}"));
|
||||
Exit::Trap(short_trap(&full))
|
||||
}
|
||||
},
|
||||
};
|
||||
// Process exit closes every file, so a clean exit commits.
|
||||
|
||||
Reference in New Issue
Block a user