Skip to content

Datastore consolidation (ADR-014 step 5)

Source of truth: docs/runbooks/datastore-consolidation.md (synced at build time — edit the original, not this copy). Identity and every product use one suite-postgres and one suite-redis:

Consumer PostgreSQL Redis
Identity suite-postgres/veltro_identity (four roles, three DSNs; the importer role has no DSN) none
VectorFlow suite-postgres/vectorflow redis://suite-redis:6379/0
Sigmatic suite-postgres/sigmatic (through sigmatic-pgbouncer in the repo compose) cache /1, queue /2
Warden suite-postgres/warden redis://suite-redis:6379/3

Product hosts and Redis indices are compose literals. The identity DSNs are the only stack environment values that name the host:

Terminal window
VELTRO_IDENTITY_MIGRATION_DATABASE_URL=postgresql://veltro_identity_owner:***@suite-postgres:5432/veltro_identity
VELTRO_IDENTITY_RUNTIME_DATABASE_URL=postgresql://veltro_identity_runtime:***@suite-postgres:5432/veltro_identity
VELTRO_IDENTITY_RECOVERY_DATABASE_URL=postgresql://veltro_identity_recovery:***@suite-postgres:5432/veltro_identity

scripts/validate_identity_credentials.py (run by make up, veltro install and veltro doctor) refuses a migration or runtime DSN whose host isn’t suite-postgres.

Suite 0.13 added the shared stores beside the eight per-product ones, then switched every consumer to them. The data moved through a protected, fenced migration that release-suite.yml dispatched as one-shots on the deployed stack (#1067).

The homelab migrated on 2026-09-27 (run 36309493050) and switched with suite 0.13.8 (komodo/veltro#52, komodo/resources#232). All four databases and all four Redis indices verified.

The per-product stores, their legacy-datastores profile and the migration one-shots were retired the same day without a soak, after full database backups. The compose files no longer define any of them.

An install still on the per-product stores

Section titled “An install still on the per-product stores”

This release can’t move it. Upgrade to suite 0.13.9 first and follow that release’s copy of this runbook, then upgrade from there. Backups taken on the per-product layout restore only with the release that took them (backup-restore.md).

docker compose up leaves the old datastore containers running as orphans. Remove them once with --remove-orphans (for example docker compose --env-file versions.env --env-file .env --profile core up -d --remove-orphans with your usual profiles). That removes containers only.

The old named volumes stay on disk, and nothing in Veltro deletes them. Once you’ve checked a backup of the shared stores and no longer need the old data, remove them with docker volume rm. The repo compose named them veltro-veltro-identity-pgdata, veltro-vf-pgdata, veltro-vf-redisdata, veltro-chad-pgdata, veltro-chad-redis-data, veltro-chad-redis-queue-data and veltro-warden-pgdata. Its warden-redis had no volume. The migration also left <project>_datastore-evidence, which is veltro_datastore-evidence when the Compose project is veltro. Hand-maintained stacks differ: the homelab Komodo stack named identity’s volume veltro-identity-pgdata and gave Warden’s Redis veltro-warden-redis-data. Check a stack’s own compose file before deleting anything.

PostgreSQL connections. SUITE_POSTGRES_MAX_CONNECTIONS (default 250) has to cover every pool that reaches the server: Sigmatic through sigmatic-pgbouncer (PGBOUNCER_DEFAULT_POOL_SIZE, 25), or without the pooler each Sigmatic process’s DATABASE_POOL_SIZE plus DATABASE_MAX_OVERFLOW; VectorFlow’s Prisma pool; Warden’s backend and worker pools; identity; the one-shot migrations; and superuser headroom. Without the pooler, Sigmatic’s four API workers, two ingest workers and two worker replicas each keep their own pool; the homelab was sized at 400 for that. Check the busiest SELECT count(*) FROM pg_stat_activity before lowering it.

Redis memory. suite-redis runs noeviction, so at maxmemory every product’s writes fail, not just one. Keep SUITE_REDIS_MAXMEMORY (default 4 GB) above used_memory_peak from INFO memory, with room for the Sigmatic queue to back up. Sigmatic’s cache relies on bounded TTLs and a bounded dead-letter stream (sigmatic#610) because the shared store never evicts.