Watch the world folder: auto spawn/upgrade, broker watch/unwatch, retire scan
ci / check (push) Failing after 7m36s
ci / check (push) Failing after 7m36s
The host watches the whole world folder recursively with the notify crate
(any writer counts, .sausage-tmp-* skipped, ~100 ms coalescing per path).
A new or changed actor/<id>/actor.wasm (or new folder actor/<id>) is
booted as at start once quiet: new = spawn (tested first), changed =
upgrade. The broker `scan` request is gone; the boot pass stays, plus a
full pass when the OS watcher overflows.
New broker requests watch/unwatch {path} (saved in actor.json `watches`)
deliver fs_changed {path, op: write|create|remove|rename, to?} from `fs`,
not routed, dropped when the mailbox is full; overflow sends every watcher
one fs_changed {path:"/actor", op:"rescan"}.
Card #91 (multi-host step 1).
This commit is contained in:
+15
-7
@@ -1,7 +1,8 @@
|
||||
//! Sausage: grow a system of WASI actors by talking to it.
|
||||
//!
|
||||
//! The host runs the broker, the native actors (`broker`, `cargo`, and the
|
||||
//! console), and one supervisor per WASM actor. See `PROTOCOL.md`.
|
||||
//! console), one supervisor per WASM actor, and the file watcher of the
|
||||
//! world folder (`watch.rs`). See `PROTOCOL.md`.
|
||||
|
||||
pub mod broker;
|
||||
pub mod candidate;
|
||||
@@ -10,6 +11,7 @@ pub mod console;
|
||||
pub mod runtime;
|
||||
pub mod supervisor;
|
||||
pub mod vfs;
|
||||
pub mod watch;
|
||||
pub mod world;
|
||||
|
||||
use std::path::Path;
|
||||
@@ -30,12 +32,13 @@ pub struct Host {
|
||||
pub world: World,
|
||||
pub broker: Arc<Broker>,
|
||||
native: Vec<tokio::task::JoinHandle<()>>,
|
||||
watcher: Option<watch::Watcher>,
|
||||
_lock: std::fs::File,
|
||||
}
|
||||
|
||||
impl Host {
|
||||
/// Start the broker, `cargo`, and every registered actor of the world at
|
||||
/// `root`. Only one host can run a world at a time.
|
||||
/// Start the broker, `cargo`, the file watcher, and every registered
|
||||
/// actor of the world at `root`. Only one host can run a world at a time.
|
||||
pub async fn start(root: &Path) -> Result<Host> {
|
||||
let world = World::new(std::path::absolute(root)?);
|
||||
if !world.exists() {
|
||||
@@ -53,10 +56,14 @@ impl Host {
|
||||
tokio::spawn(broker.clone().run_actor(broker.open_mailbox("broker"))),
|
||||
tokio::spawn(cargo.run_actor(broker.clone(), broker.open_mailbox(cargo_actor::ID))),
|
||||
];
|
||||
// Watch first, so that no change during the boot pass is lost.
|
||||
let watcher = watch::start(broker.clone())
|
||||
.inspect_err(|e| broker.host_error(&format!("no file watching: {e}")))
|
||||
.ok();
|
||||
for change in broker.scan().await {
|
||||
eprintln!("sausage: {change}");
|
||||
}
|
||||
Ok(Host { world, broker, native, _lock: lock })
|
||||
Ok(Host { world, broker, native, watcher, _lock: lock })
|
||||
}
|
||||
|
||||
/// Register a native actor with the ID `id` and return its mailbox.
|
||||
@@ -64,9 +71,10 @@ impl Host {
|
||||
self.broker.open_mailbox(id)
|
||||
}
|
||||
|
||||
/// Stop the broker and `cargo` (with the requests they still run), then
|
||||
/// every actor, gracefully.
|
||||
pub async fn stop(self) {
|
||||
/// Stop the file watcher, the broker and `cargo` (with the requests they
|
||||
/// still run), then every actor, gracefully.
|
||||
pub async fn stop(mut self) {
|
||||
drop(self.watcher.take());
|
||||
for task in &self.native {
|
||||
task.abort();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user