From 7c6bf321861be00f7afb414c16ea6815f03e884d Mon Sep 17 00:00:00 2001 From: Ravi Tharuma <25951435+RaviTharuma@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:48:10 +0200 Subject: [PATCH] docs(docker): document SQLite single-replica HA limits (#10817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution! --- .../10350-sqlite-single-replica-ha.md | 1 + docs/guides/DOCKER_GUIDE.md | 23 +++++++++++++++++++ docs/ops/SQLITE_RUNTIME.md | 14 +++++++++++ 3 files changed, 38 insertions(+) create mode 100644 changelog.d/maintenance/10350-sqlite-single-replica-ha.md diff --git a/changelog.d/maintenance/10350-sqlite-single-replica-ha.md b/changelog.d/maintenance/10350-sqlite-single-replica-ha.md new file mode 100644 index 0000000000..9b158d5787 --- /dev/null +++ b/changelog.d/maintenance/10350-sqlite-single-replica-ha.md @@ -0,0 +1 @@ +- **docs(docker):** document default SQLite as single-replica / HA-unsupported, including Recreate and HEALTHCHECK session blast radius ([#10350](https://github.com/diegosouzapw/OmniRoute/issues/10350)) diff --git a/docs/guides/DOCKER_GUIDE.md b/docs/guides/DOCKER_GUIDE.md index 464aa55319..fde782dbf9 100644 --- a/docs/guides/DOCKER_GUIDE.md +++ b/docs/guides/DOCKER_GUIDE.md @@ -22,6 +22,7 @@ lastUpdated: 2026-06-28 - [Docker Compose with Caddy (HTTPS)](#docker-compose-with-caddy-https-auto-tls) - [Cloudflare Quick Tunnel](#cloudflare-quick-tunnel) - [Image Tags](#image-tags) +- [Availability: default SQLite is single-replica](#availability-default-sqlite-is-single-replica) - [Important Notes](#important-notes) --- @@ -465,6 +466,28 @@ docker compose up -d A release-branch build can never move `latest`; only an eligible stable semantic version may promote the stable pointer. The `next` images retain the release image inspection and blocking CRITICAL-vulnerability gate. +## Availability: default SQLite is single-replica + +Stock Docker / Kubernetes OmniRoute is **one Node process + one SQLite writer**. High availability is **not supported** on that topology. + +| Constraint | Consequence | +| --- | --- | +| Single writer | Do **not** run multiple replicas against the same SQLite file. That corrupts the DB. | +| Recreate / restart / HEALTHCHECK kill | **Full outage** of in-flight SSE, dashboard sessions, and in-memory state. Every connected client drops. | +| Same event loop as `/healthz` | A busy catalog or compression tick can delay probes; a short timeout then restarts the **only** replica. | + +**Probe matrix** (see also [Kubernetes probe recommendations](../ops/MONITORING_GUIDE.md#kubernetes-probe-recommendations)): + +| Probe | Target | Do not use | +| --- | --- | --- | +| Liveness | TCP on `PORT` (default `20128`), or soft HTTP `/healthz` | `/api/monitoring/health` | +| Readiness | HTTP `GET /healthz` | Tight timeouts that treat event-loop busy as dead | +| Deep / humans | `/api/monitoring/health` | Automated kubelet liveness | + +**Upgrades:** expect every session to drop. Drain clients if you can; there is no rolling update on default SQLite. Compose `restart: unless-stopped` plus Docker `HEALTHCHECK` will also replace the only process when the container is Unhealthy — same blast radius. + +External Postgres / multi-writer HA is **not** a documented stock path. If you need HA, keep a single replica or run a topology the project has tested and documented separately. + ## Important Notes - **SQLite WAL Mode:** `docker stop` should be allowed to finish so OmniRoute can checkpoint the latest changes back into `storage.sqlite`. The bundled Compose files already set a 40s stop grace period. If you run the image directly, keep `--stop-timeout 40`. diff --git a/docs/ops/SQLITE_RUNTIME.md b/docs/ops/SQLITE_RUNTIME.md index e2e6a412da..ab31996fb2 100644 --- a/docs/ops/SQLITE_RUNTIME.md +++ b/docs/ops/SQLITE_RUNTIME.md @@ -80,3 +80,17 @@ Implementation: - `bin/cli/runtime/index.mjs` — startup orchestrator (`warmUpRuntimes()`) - `scripts/postinstall.mjs` — npm post-install hook (non-fatal warm-up) - `src/lib/db/core.ts` — `ensureDbInitialized()` / `getDriverInfo()` exports + +## Single-writer topology (HA unsupported) + +The driver fallback chain above still runs in **one process**. Default SQLite +OmniRoute is a **single writer**: + +- Do not attach two OmniRoute replicas to the same `storage.sqlite` file. +- A container restart, Recreate deploy, OOM kill, or HEALTHCHECK restart drops + every in-flight SSE session. There is no session drain on the stock path. +- Orchestrator liveness that treats a slow `/healthz` as dead will kill the only + replica. Prefer TCP liveness + HTTP `/healthz` readiness. See + [Docker Guide — availability](../guides/DOCKER_GUIDE.md#availability-default-sqlite-is-single-replica) + and [Kubernetes probe recommendations](./MONITORING_GUIDE.md#kubernetes-probe-recommendations). +