feat: multi-process safety + read-only inspector mode
Filesystem storage now enforces single-writer, many-reader semantics. A second writer on the same data directory throws at init time with the holder's PID, hostname, and heartbeat — replacing the previous silent stale-reads failure mode. - New: `Brainy.openReadOnly()` — coexists with a live writer, every mutation throws clearly. - New: writer lock at `<rootDir>/locks/_writer.lock` with 10s heartbeat and stale-detection (PID liveness + heartbeat freshness). - New: cross-process flush-request RPC (filesystem-based, no signals) so inspectors can force fresh state on demand. - New: `brain.stats()`, `brain.explain(findParams)`, `brain.health()` for operator-facing introspection. - New: `brainy inspect` CLI with 13 subcommands (stats, find, get, relations, explain, health, sample, fields, dump, watch, backup, repair, diff), all read-only by default. - Same-PID re-opens allowed with a warning (preserves test "simulate restart" patterns). - Storage instances passed directly via `storage: new MemoryStorage()` are now honoured instead of silently falling through to the filesystem auto-detect path. Brainy + Cortex compose under this model — the lock covers both because they share `rootDir`, Cortex segments are immutable mmap files, and MANIFEST updates use atomic-rename.
This commit is contained in:
parent
1bc6a430c7
commit
4fcdc0fef3
12 changed files with 2342 additions and 7 deletions
35
README.md
35
README.md
|
|
@ -349,6 +349,41 @@ npm install @soulcraft/brainy # Node.js — fully supported
|
|||
|
||||
> **Deprecation Notice:** Browser support (OPFS, Web Workers, WASM embeddings) is deprecated in v7.10.0 and will be removed in v8.0.0. Brainy v8+ will be server-only.
|
||||
|
||||
## Single-Writer Model
|
||||
|
||||
Brainy is **single-writer, many-reader** on filesystem storage. One writer
|
||||
holds an exclusive lock on the data directory; any number of readers can
|
||||
inspect it concurrently. Opening a second writer throws with the PID of the
|
||||
existing one.
|
||||
|
||||
```typescript
|
||||
// Live application — writer mode is the default
|
||||
const brain = new Brainy({ storage: { type: 'filesystem', rootDirectory: '/data/brain' } })
|
||||
await brain.init()
|
||||
|
||||
// Out-of-band diagnostics from a separate process — safe to run while the
|
||||
// writer is live
|
||||
const reader = await Brainy.openReadOnly({
|
||||
storage: { type: 'filesystem', rootDirectory: '/data/brain' }
|
||||
})
|
||||
await reader.requestFlush({ timeoutMs: 5000 })
|
||||
const stats = await reader.stats()
|
||||
```
|
||||
|
||||
For incident debugging, use the `brainy inspect` CLI:
|
||||
|
||||
```bash
|
||||
brainy inspect stats /data/brain
|
||||
brainy inspect find /data/brain --where '{"entityType":"booking"}'
|
||||
brainy inspect explain /data/brain --where '{"entityType":"booking"}'
|
||||
brainy inspect health /data/brain
|
||||
```
|
||||
|
||||
See [the multi-process model](docs/concepts/multi-process.md) and the
|
||||
[inspection guide](docs/guides/inspection.md) for the full story, including
|
||||
stale-lock detection, the cross-process flush RPC, and what's not yet
|
||||
enforced on cloud storage backends.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions! See **[CONTRIBUTING.md](CONTRIBUTING.md)** for guidelines.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue