Files
alkstore/docs/architecture/deployment.md
T

7.5 KiB
Raw Blame History

status, last_updated
status last_updated
draft 2026-10-06

Deployment

What a deployer must know to size, run, and reason about alkstore engines: host semantics, connection budgets, durability knobs, and where engine differences may honestly surface in the contract. The capability-surface decision is resolved (ADR-016, 2026-10-06): no runtime capability surface — this document's matrix is (with the engine crates' own docs) where the honest boundary lives; this document holds the facts.

Host semantics

Engine Host posture Notes
SQLite single-machine, file-backed NFS two-writers unsupported (honker's honesty posture, inherited, ADR-003). Cross-process on one host is verified POC ground (data_version is cross-process by nature).
Postgres multi-host native Nothing assumes a shared host; POC #2 ran all-through-network (docker bridge) with the same properties (ADR-004).

The unified trait must not pretend SQLite is multi-host — and it does not: ADR-016 resolves that honesty to compile-time engine identity (the engine crate a binary depends on is the deployment statement) plus this documented matrix. There is no Store::capabilities() — the trait's shape constrains where capability differences can surface (ADR-006), and the resolution is: nowhere at runtime.

Options for OQ-08, with their outcome (ADR-016):

  1. Compile-time only — a consumer chooses an engine crate at dependency time; the engine's docs carry its deployment facts. Smallest contract; nothing runtime to match on. Adopted — together with (3); the two compose (engine docs serve the consumer choosing the dependency, the matrix serves the operator choosing the topology).
  2. Store::capabilities() — a runtime description (payload limits, wake cadence knobs, host semantics). Lets a consumer adapt (e.g., chunk large notify payloads) but adds a contract surface all engines must keep honest. Rejected — field-by-field under ADR-008 §5's act-differently rule, and no consumer-inventory row names a runtime-adapt need (ADR-016 §2).
  3. Deployment matrix only (this document) — no API surface. The honest-middle choice; matches the ecosystem's doc-first posture but provides no programmatic guard. Adopted (with (1)) — the "programmatic guard" gap is closed where it can honestly be: the engine-crate dependency edge cannot drift out of sync with the truth it states; the misconfiguration case (SQLite as shared network storage) follows the family's deployment-asserts-truth posture — documented detection symptom, no fabricated runtime machinery (ADR-016 §3).

Connection budgets

SQLite engine

  • Connections are in-process (writer + reader pool + watcher thread owning a connection). No external budget lines; the file lock is the OS-level resource.

Postgres engine

Connection class Count Notes
Pool max_size per process claims/queries via deadpool
Listener +1 per LISTEN-ing process non-pooled, dedicated; pooled connections cannot carry LISTEN (deadpool#360, test-pinned — ADR-004)
— — Sizing rule: max_size + 1 per process; verify end-to-end accounting (POC #2's pgdiag-st-4: pool 6 + 1 listener + probe conns = exact server-side count)

Shared-server co-tenancy (the alkblobs ADR-008 precedent — /workspace/@alkdev/alkblobs/docs/architecture/decisions/ — consumer tables co-tenant the pg instance) is supported and expected — the naming / reserved namespace contract protects reserved names; queue/stream/lock/schedule tables live in one engine-owned PostgreSQL schema (default alkstore, per-engine option) — layout per ADR-010 §8 (resolved from queues.md's namespace bullet).

Durability knobs

Engine Knob Shape
SQLite synchronous WAL + NORMAL shipped (ADR-003); FULL is available consumer-side for stricter durability; commit fsyncs land at WAL checkpoints (the ~1000-commit spike cadence, POC #1)
Postgres synchronous_commit per-session knob; on is ship config (p50 2.40 ms seam); off trades max-tail (40.9 ms) for slightly better p50 — measured, honest trade (ADR-004); session-level SET mechanics POC-verified

These are engine-configuration concerns, not trait surface. What part of engine config is contract-level shape vs engine-crate docs is decided: constructors and option structs live in the engine crates; the contract is the trait the constructor returns (ADR-008 §6).

Toolchain / platform notes

Note Engine Affects
rusqlite 0.40.x needs rustc ≥ 1.99 SQLite any binary linking alkstore-sqlite (ADR-003)
bundled-sqlite adds a C build (~10 s dev, cacheable) SQLite build/CI time
libsqlite3-sys collision with sqlx today any mixed-driver binary structurally avoided (ADR-001 single-driver rule)
Listener application_name set for diagnosability (kill-targetable) Postgres ops runbooks (ADR-004)

Consumer-facing latency profile (indicative, POC-measured)

From both POCs (single-box, relative shapes are the deliverable — ADR-003 and ADR-004 carry the full tables):

  • Tx seam: SQLite ~0.35 ms p50; Postgres ~2.4 ms p50 (ship config).
  • Wake: ~1.1–2.2 ms p50 both engines at default cadence.
  • Queue claim: LISTEN-driven 3–6 ms p50 (pg); poll-only interval-bound (32–50 ms at a 50 ms poll).
  • Absolute numbers will differ per hardware/network; they set expectations of order, not SLAs — contract docs must not bake them in (ADR-007's pg-POC note).

Design Decisions

ADR Decision Summary
001 Crate split single-driver binaries shape the matrix
003 SQLite driver bundling, toolchain floor
004 Postgres driver listener budget line, forwarder posture
006 Wake contract where capability differences may surface
008 Contract v1 constructor/options in engine crates; no capability surface in v1 (OQ-08; resolved by ADR-016)
016 Deployment honesty no runtime capability surface — compile-time identity + this matrix; PayloadTooLarge is the one runtime asymmetry carriage

Open Questions

Open questions are tracked in open-questions.md. Key questions affecting this document:

  • OQ-08: capability-surface shape — resolved (2026-10-06, ADR-016): no runtime capability surface; compile-time engine identity + this matrix; re-entry via a consumer-inventory row naming a runtime-adapt need.