Files
alkstore/docs/architecture/deployment.md
T

118 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: draft
last_updated: 2026-10-05
---
# 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* (how much of this the trait exposes) is
OQ-08's; this document holds the facts and the decision's frame.
## Host semantics
| Engine | Host posture | Notes |
|---|---|---|
| SQLite | **single-machine**, file-backed | NFS two-writers unsupported (honker's honesty posture, inherited, [ADR-003](decisions/003-sqlite-driver.md)). 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](decisions/004-postgres-driver.md)). |
The unified trait must not pretend SQLite is multi-host — but whether
that honesty lives as runtime capability flags, compile-time engine
knowledge, or a documented matrix only is OQ-08
([ADR-006](decisions/006-wake-and-delivery-contract.md) note: the
trait's shape constrains where capability differences can surface).
Options for OQ-08, with their shape:
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.
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.
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.
## 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](decisions/004-postgres-driver.md)) |
| — | — | 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](core-contract.md#naming--reserved-namespace)
protects reserved names; queue/stream/lock tables are schema-named to
avoid collisions (layout decision in [queues.md](queues.md), OQ-05's
namespace bullet).
## Durability knobs
| Engine | Knob | Shape |
|---|---|---|
| SQLite | `synchronous` | WAL + `NORMAL` shipped ([ADR-003](decisions/003-sqlite-driver.md)); 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](decisions/004-postgres-driver.md)); 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](decisions/008-contract-v1-pinning.md) §6).
## Toolchain / platform notes
| Note | Engine | Affects |
|---|---|---|
| rusqlite 0.40.x needs rustc ≥ 1.99 | SQLite | any binary linking `alkstore-sqlite` ([ADR-003](decisions/003-sqlite-driver.md)) |
| `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](decisions/001-crate-split.md) single-driver rule) |
| Listener `application_name` set for diagnosability (kill-targetable) | Postgres | ops runbooks ([ADR-004](decisions/004-postgres-driver.md)) |
## Consumer-facing latency profile (indicative, POC-measured)
From both POCs (single-box, relative shapes are the deliverable —
[ADR-003](decisions/003-sqlite-driver.md) and
[ADR-004](decisions/004-postgres-driver.md) 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](decisions/007-transactional-seam.md)'s pg-POC
note).
## Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| [001](decisions/001-crate-split.md) | Crate split | single-driver binaries shape the matrix |
| [003](decisions/003-sqlite-driver.md) | SQLite driver | bundling, toolchain floor |
| [004](decisions/004-postgres-driver.md) | Postgres driver | listener budget line, forwarder posture |
| [006](decisions/006-wake-and-delivery-contract.md) | Wake contract | where capability differences may surface |
| [008](decisions/008-contract-v1-pinning.md) | Contract v1 | constructor/options in engine crates; no capability surface in v1 (OQ-08) |
## Open Questions
Open questions are tracked in
[open-questions.md](open-questions.md). Key
questions affecting this document:
- **OQ-08**: capability-surface shape — compile-time vs runtime flags
vs matrix-only (open)