feat(544): shipped compose files run on the orchestrator's defaults; the app waits for its database itself

Brings the three compose files in line with rule 198 (milestone 544,
step 6203, at the operator's request):
- no healthcheck on the app or the database, so a slow pg_isready on
  stalled storage can no longer get a working database killed;
- no deploy.restart_policy in the Swarm file, so Swarm's default
  (condition: any) restarts clean exits too, instead of on-failure with
  max_attempts leaving the app down;
- depends_on is plain start order; restart: unless-stopped stays on the
  plain-Compose files (Swarm ignores it), and the dev app gains it.

The orchestrator used to be what retried a container that started before
Postgres was ready. That is now the app's job: alembic/env.py calls
services/db_ready.wait_for_database before migrating. It retries refused
connections, unresolved hosts, connect timeouts and "the database system
is starting up" with 1-2-4-...-10s spacing for up to 300s, then exits
non-zero; a wrong password or missing database fails at once.
Per-request recovery is the engine's pool_pre_ping.

Also fixes the dev compose database image: postgres:16-alpine has no
vector extension, so migrations could not run against it. It now uses
pgvector/pgvector:pg17 like the other two files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 19:15:20 -04:00
co-authored by Claude Opus 5.5
parent 9bb3b68cc4
commit cba2c24612
6 changed files with 184 additions and 57 deletions
+4 -17
View File
@@ -4,8 +4,8 @@ services:
ports:
- "5000:5000"
depends_on:
db:
condition: service_healthy
- db
restart: unless-stopped
volumes:
- app_data:/data
# Or a bind mount, for direct host access to the app's data:
@@ -15,15 +15,10 @@ services:
SECRET_KEY: "${SECRET_KEY:-dev-secret-change-me}"
# Optional: a SearXNG instance to list as the web-search backend in Integrations.
# SEARXNG_URL: "http://searxng:8080"
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/api/health')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
db:
image: postgres:16-alpine
# Postgres 17 with the vector extension Scribe needs.
image: pgvector/pgvector:pg17
stop_grace_period: 120s
restart: unless-stopped
volumes:
@@ -32,14 +27,6 @@ services:
POSTGRES_USER: ${POSTGRES_USER:-scribe}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-scribe}
POSTGRES_DB: ${POSTGRES_DB:-scribe}
# Lenient on purpose: health only orders app startup, so a stalled check
# must not get the database killed.
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-scribe}"]
interval: 30s
timeout: 10s
retries: 10
start_period: 180s
volumes:
pgdata: