diff --git a/hive-jobq/README.md b/hive-jobq/README.md index eac5c262..c5cd135c 100644 --- a/hive-jobq/README.md +++ b/hive-jobq/README.md @@ -1,7 +1,7 @@ # hive-jobq -A persistent job-DAG scheduler, extracted from hive-c0re's in-tree `job_queue` -as a **domain-agnostic** library. It schedules a single persistent graph of +A job-DAG scheduler, extracted from hive-c0re's in-tree `job_queue` +as a **domain-agnostic** library. It schedules a single in-memory graph of nodes over named resources; it knows nothing about containers, rebuilds, or any hyperhive type — the node payload `N` and resource name `R` are both generic, so the caller supplies its own domain. @@ -15,7 +15,13 @@ kinds, wires deps, and supplies a runner; the scheduler decides what can start. ## Model -One **persistent graph** for the whole system, not a DAG per job. Enqueuing +**Runtime-only: nothing writes this graph to disk.** The serde impls exist for +the wire projection (`hive-jobq-wire`) and a possible future store; no caller +loads one, so ids and timestamps are stable within a run, not across restarts. +hive-c0re constructs an empty graph every boot and re-derives desired state with +its reconcile sweep. + +One **shared graph** for the whole system, not a DAG per job. Enqueuing inserts a self-contained sub-DAG and returns the ids of the nodes the job *asked* for, in the order it named them; the scheduler runs a continuous loop, starting every node whose deps are satisfied: @@ -35,18 +41,20 @@ for the acquiring node *plus its whole parent subtree*, and a descendant needing a resource an ancestor already holds re-uses that grant (a re-entrant borrow, one branch at a time) rather than taking a fresh unit. -A `NodeId` is opaque, stable, and monotonic (safe to persist). The scheduler is +A `NodeId` is opaque, stable and monotonic **within a run** — a fresh process +mints ids from zero, so an id stored outside it is a historical record, not a +handle that will resolve later. The scheduler is single-threaded — it owns the resource table and mutates it directly. ## Shape -- **`Graph`** — the persistent node store. `insert` mints ids and +- **`Graph`** — the in-memory node store. `insert` mints ids and validates dep/parent references; `set_state` is the single state-transition choke point (and where each node's lifecycle timestamps — `started_at` / `finished_at`, `DateTime` — are stamped). - **`Node`** — `{ id, parent, payload, deps, state, started_at, - finished_at, error }`. All fields public; derives serde for persistence + the - wire. + finished_at, error }`. All fields public; derives serde for the wire + projection (and so a store could be added — nothing calls one today). - **`Scheduler`** — drives the graph: `settle()` starts every ready node (acquiring resources atomically), `complete(id, outcome)` reports a finished node's result and rolls terminality up the parent chain, releasing grants once