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:
+18
-14
@@ -24,6 +24,9 @@ pub struct ProcessInfo {
|
||||
}
|
||||
pub(crate) struct Process {
|
||||
pub(crate) info: ProcessInfo,
|
||||
pub(crate) memory: sausage_vfs::Memory,
|
||||
pub(crate) files: sausage_vfs::Process,
|
||||
pub(crate) store_ended: watch::Sender<bool>,
|
||||
pub(crate) input: Option<mpsc::UnboundedSender<Value>>,
|
||||
pub(crate) abort: Option<tokio::task::AbortHandle>,
|
||||
pub(crate) caller: String,
|
||||
@@ -31,19 +34,19 @@ pub(crate) struct Process {
|
||||
pub(crate) answer: Option<oneshot::Sender<RpcResult>>,
|
||||
pub(crate) ended: watch::Sender<bool>,
|
||||
}
|
||||
pub(crate) struct ProcessGuard {
|
||||
pub(crate) host: Host,
|
||||
pub(crate) pid: String,
|
||||
}
|
||||
impl Drop for ProcessGuard {
|
||||
fn drop(&mut self) {
|
||||
self.host.finish(&self.pid, "process task ended");
|
||||
}
|
||||
}
|
||||
|
||||
impl Host {
|
||||
/// Remove a process and release its locks before asynchronous journal completion.
|
||||
pub(crate) fn finish(&self, pid: &str, status: &str) {
|
||||
/// Called only after the execution task ends. Wait for the store and file operations before releasing locks.
|
||||
pub(crate) async fn finish(&self, pid: &str, status: &str) {
|
||||
let (files, mut store_ended) = {
|
||||
let mut state = self.0.state.lock().unwrap();
|
||||
let Some(p) = state.processes.get_mut(pid) else {
|
||||
return;
|
||||
};
|
||||
p.info.state = "stopping".into();
|
||||
(p.files.clone(), p.store_ended.subscribe())
|
||||
};
|
||||
let _ = store_ended.wait_for(|ended| *ended).await;
|
||||
files.idle().await;
|
||||
let mut state = self.0.state.lock().unwrap();
|
||||
let process = state.processes.remove(pid);
|
||||
if let Some(p) = process {
|
||||
@@ -106,13 +109,14 @@ impl Host {
|
||||
}
|
||||
/// Abort a process task and perform its ended-state cleanup.
|
||||
pub(crate) fn kill(&self, pid: &str) {
|
||||
if let Some(p) = self.0.state.lock().unwrap().processes.get(pid) {
|
||||
if let Some(p) = self.0.state.lock().unwrap().processes.get_mut(pid) {
|
||||
p.info.state = "stopping".into();
|
||||
p.input.take();
|
||||
self.0.journal.write(pid, &p.info.plugin, "core", "kill");
|
||||
if let Some(a) = &p.abort {
|
||||
a.abort();
|
||||
}
|
||||
}
|
||||
self.finish(pid, "killed");
|
||||
}
|
||||
/// Stop every process in parallel and wait for journal writes to finish.
|
||||
pub async fn stop(&self) {
|
||||
|
||||
Reference in New Issue
Block a user