core: sausage-vfs per process (/, /proc, /self, /run), activation, graph, watcher, upgrades
- /proc is a core layer: core/ (PROTOCOL.md, graph.json, graph.dot, locks.json, plugins/<name>/discover.json and client.rs) and one folder per process (info.json, log, and its /self files). - Locks are released only after the task ended, the store dropped, and in-flight file operations returned. - core.activate and core.revert with copies, discovery, compatibility checks of imports and consumers, groups, force. An admission gate makes the snapshot of old processes complete. - Graph of discover documents by hash, refreshed by a file watcher. - Upgrades: grace periods (x-sausage-grace), stop, service restarts, rpc.retired. - SDK plugins in the real core (cli/tests/sdk.rs).
This commit is contained in:
+34
-19
@@ -1,31 +1,46 @@
|
||||
//! Services: the calls in `/config/boot.json` (PROTOCOL.md section 8). The
|
||||
//! core starts them in order at boot.
|
||||
//! Ordered boot services and their identities for upgrade restarts (PROTOCOL.md section 8).
|
||||
use crate::Host;
|
||||
use serde_json::{Value, json};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Service {
|
||||
pub(crate) method: String,
|
||||
pub(crate) params: Value,
|
||||
pub(crate) request: Value,
|
||||
}
|
||||
impl Host {
|
||||
/// Start each service of `/config/boot.json` as a detached call with the
|
||||
/// parent `core`, in order. A failure goes to the journal, and boot
|
||||
/// continues.
|
||||
/// Starts discovery in the background, then waits for each boot service in order.
|
||||
pub(crate) async fn boot(&self) -> anyhow::Result<()> {
|
||||
self.watch_plugins()?;
|
||||
let boot: Vec<Value> = serde_json::from_slice(
|
||||
&tokio::fs::read(self.0.world.root.join("config/boot.json")).await?,
|
||||
)?;
|
||||
for service in boot {
|
||||
let result = self
|
||||
.route(
|
||||
"core".into(),
|
||||
Some(json!(Uuid::now_v7().to_string())),
|
||||
service["method"].as_str().unwrap_or("").into(),
|
||||
service["params"].clone(),
|
||||
true,
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = result {
|
||||
self.0.journal.write("core", "core", "core", &e.to_string());
|
||||
}
|
||||
self.start_service(
|
||||
service["method"].as_str().unwrap_or("").into(),
|
||||
service["params"].clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Records a unique request identity before the service can answer or exit.
|
||||
pub(crate) async fn start_service(&self, method: String, params: Value) {
|
||||
let request = json!(uuid::Uuid::now_v7().to_string());
|
||||
self.0.state.lock().unwrap().services.push(Service {
|
||||
method: method.clone(),
|
||||
params: params.clone(),
|
||||
request: request.clone(),
|
||||
});
|
||||
self.0
|
||||
.journal
|
||||
.write("core", "core", "core", &format!("service start {method}"));
|
||||
if let Err(error) = self
|
||||
.route("core".into(), Some(request), method, params, true)
|
||||
.await
|
||||
{
|
||||
self.0
|
||||
.journal
|
||||
.write("core", "core", "core", &format!("service failed {error}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user