Design: split into two homebrew services - puller + reads - around the shared DuckDB file #3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally filed by @coilysiren on 2026-05-20T06:58:51Z - https://github.com/coilysiren/session-lattice/issues/27
Problem
Today
session_lattice/service.pyputs the puller and the read API in one process.create_app()spawnsrefresh.run(config, stop_event)as an asyncio task inside the FastAPI lifespan; the same uvicorn worker serves HTTP and holds the DuckDB RW handle.That's fine pre-cable, but once the puller actually pulls from repo-recall:
Design: split into two homebrew services around the shared
.duckdbfileDuckDB is an embedded library + a file. Many processes can attach read-only to the same file concurrently; only one can hold read-write. So the natural cleave is:
session-lattice-puller- long-running worker. Holds the RW handle. Pulls fromSESSION_LATTICE_REPO_RECALL_URLon a tick, runs the per-view materialization. No HTTP listener. Probably no port at all (status via logs and a stamp row in DuckDB).session-lattice-reads- FastAPI HTTP server on the existing port (7778 staging / 7781 dev / tailnet prod). Opens RO handles per request. Never writes.Both ship from this repo, both consume the same
session_latticepackage, both target the sameSESSION_LATTICE_HOME. Differentbin/entry points (session-lattice-pullerandsession-lattice-reads, or one binary withserve-reads/serve-pullersubcommands - cleaner).Homebrew shape
Two
service doblocks inFormula/session-lattice.rb(modern brew supports this via per-servicename), or one block per env variant. Each block keepskeep_alive true. mcporter slots stay pointed at the reads-service ports.~/.session-lattice/session-lattice.duckdbis the contract surface between them. DuckDB's WAL semantics mean RO readers see a snapshot at attach time, so brief writer pauses are invisible to in-flight read handlers.Rollout order
This lands as part of, not before, the puller's first real implementation:
serve-puller/serve-readssubcommands to the CLI, keepserveas a transitional wrapper that runs both in one process (so existing brew installs keep working).refresh.pyis a stub).service doblock, retireservein favor of the split.brew services start session-lattice-puller.Out of scope
The MCP host (
/mcpendpoint that mcporter points at) lives on the reads service. The puller doesn't serve HTTP.Touches: AGENTS.md (rule about "brew binary is the contract" generalizes to both services). README install steps grow a second
brew services start. coilysiren/session-lattice#23 (no-uv-run-from-checkout wording) needs revisiting once the split lands.