Host: fixes from the review, with regression tests
- one live instance per actor: check after the lock; dropping an instance kills it - state snapshots keep target/ and .git/; only source copies skip them - one shutdown deadline; output during shutdown is still routed - deliveries route stdout meanwhile; a stuck stdin kills the instance (no partial lines) and the sender gets undeliverable; control requests are not blocked by a stuck delivery - Host::stop aborts running broker and cargo requests first - compile a version before installing it; roll back if it does not start - unique archive names; a failed archive keeps the actor manageable - commit on close: truncate without create; directory renames - candidates see SAUSAGE_VERSION and the existing state of a new actor - the host publishes PROTOCOL.md at /actor/broker/public/
This commit is contained in:
+9
-14
@@ -18,7 +18,7 @@ use std::time::Instant;
|
||||
use anyhow::{Context, Result, anyhow, bail};
|
||||
use serde_json::{Value, json};
|
||||
use tokio::process::Command;
|
||||
use tokio::sync::{Mutex, mpsc};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use include_dir::{Dir, include_dir};
|
||||
|
||||
@@ -38,17 +38,16 @@ pub struct BuildOutput {
|
||||
pub warnings: String,
|
||||
}
|
||||
|
||||
/// All builds share one target folder, so they run one at a time.
|
||||
pub struct Cargo {
|
||||
world: World,
|
||||
/// One build at a time: all builds share one target folder.
|
||||
lock: Mutex<()>,
|
||||
}
|
||||
|
||||
impl Cargo {
|
||||
/// Create the actor and install the SDK of this host into `data/sdk/`.
|
||||
pub fn new(world: World) -> Result<Self> {
|
||||
write_dir(&SDK, &world.data_dir(ID).join("sdk"))?;
|
||||
Ok(Self { world, lock: Mutex::new(()) })
|
||||
Ok(Self { world })
|
||||
}
|
||||
|
||||
/// Build the crate in `source` (a host path) and publish the `.wasm` file
|
||||
@@ -57,12 +56,11 @@ impl Cargo {
|
||||
if !source.join("Cargo.toml").is_file() {
|
||||
bail!("{} has no Cargo.toml", source.display());
|
||||
}
|
||||
let _guard = self.lock.lock().await;
|
||||
let started = Instant::now();
|
||||
let data = self.world.data_dir(ID);
|
||||
let key = format!("{:016x}", fxhash(source.to_string_lossy().as_bytes()));
|
||||
let build_dir = data.join("work").join(&key);
|
||||
world::replace_tree(source, &build_dir)?;
|
||||
world::replace_source(source, &build_dir)?;
|
||||
let manifest = build_dir.join("Cargo.toml");
|
||||
std::fs::write(&manifest, prepare_manifest(&std::fs::read_to_string(&manifest)?, Some(&data.join("sdk")))?)?;
|
||||
|
||||
@@ -100,16 +98,13 @@ impl Cargo {
|
||||
Ok(BuildOutput { wasm: dest, seconds: started.elapsed().as_secs_f64(), warnings: strip_progress(&stderr) })
|
||||
}
|
||||
|
||||
pub async fn run_actor(self: Arc<Self>, broker: Arc<Broker>, mut mailbox: mpsc::Receiver<Envelope>) {
|
||||
/// The native `cargo` actor. Builds run one at a time, in order.
|
||||
pub async fn run_actor(self, broker: Arc<Broker>, mut mailbox: mpsc::Receiver<Envelope>) {
|
||||
while let Some(env) = mailbox.recv().await {
|
||||
let this = self.clone();
|
||||
let broker = broker.clone();
|
||||
tokio::spawn(async move {
|
||||
let body = this.handle(&broker, &env).await.unwrap_or_else(|e| {
|
||||
json!({"type": "build_failed", "source": env.body.get("source"), "errors": format!("{e:#}")})
|
||||
});
|
||||
broker.send(ID, Some(&env.from), None, Some(&env.id), body);
|
||||
let body = self.handle(&broker, &env).await.unwrap_or_else(|e| {
|
||||
json!({"type": "build_failed", "source": env.body.get("source"), "errors": format!("{e:#}")})
|
||||
});
|
||||
broker.send(ID, Some(&env.from), None, Some(&env.id), body);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user