Commit Graph

6 Commits

Author SHA1 Message Date
benvin da23ba9f4a Merge pull request 'Add read/write splitting to the pg module' (#2) from benvin/pg-rw-split into main
Reviewed-on: #2
v0.1.0
2026-08-31 23:11:19 +10:00
benvin 5a23e0d069 Merge pull request 'Add the golib scaffold and the pg module' (#1) from benvin/initial-pg into main
Reviewed-on: #1
2026-08-31 23:08:37 +10:00
unkin-agent 02233919d7 Address review findings on the pg read/write split
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Name the replica host variable that was actually resolved. lookup falls
back from the prefixed name to the bare one, but the ambiguous-replica
error printed the prefixed form unconditionally, so a deployment setting
APP_DATABASE_URL alongside a bare DB_RO_HOST was told to go and look at
APP_DB_RO_HOST, which is not in its environment. lookupNamed reports the
variable the value came from and the error names that one.

Build the replica pool before the primary in NewCluster. pgxpool
connects lazily, so this dials nothing, but it parses the replica DSN: a
mistyped one now fails before the primary is opened, which removes the
cleanup branch that closed a primary pool nobody could observe and makes
the failure testable through the public constructor. A primary that
cannot be reached closes the lazy replica pool on the way out.
2026-08-31 23:00:24 +10:00
unkin-agent 5c23db8885 Add read/write splitting to the pg module
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
pg.Cluster wraps a primary pool and an optional read-replica pool.
Routing is explicit — Read(), Write(), Primary() — with no SQL
inspection: statement text misroutes CTE writes and SELECT ... FOR
UPDATE in both directions.

An unhealthy replica falls back to the primary behind a ping-based
circuit that retries on a doubling backoff window, and migrations always
run through Write().

pg.ClusterDSNsFromEnv resolves both endpoints from the environment,
naming the read-only host explicitly rather than deriving it from the
primary's.
2026-08-31 22:44:10 +10:00
unkin-agent d59dcbe74e Add the golib scaffold and the pg module
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Stand up the shared library with its first module: the Postgres plumbing
every service currently copy-pastes — the DSN builder, the pool
constructor, and the migration runner arrproxy proved out.

- Add pg.DSNFromEnv, generalising the identical Sprintf builders in
  encapi, artifactapi and forgebot into one prefixed lookup with
  DATABASE_URL passthrough and libpq fallbacks.
- Add pg.New and pg.NewMigrated, which ping before returning so an
  unreachable server fails at startup rather than on the first query.
- Add pg.Migrate, lifting arrproxy's runner verbatim in semantics and
  generalising the hardcoded advisory-lock key to FNV-1a/64 of a
  caller-supplied name and the embedded set to an fs.FS.
- Add pg/pgtest, unifying the encapi and artifactapi testcontainers
  helpers, with SkipIfShort so container-backed tests self-skip on the
  Docker-less Kubernetes runners.
- Add the Makefile, README and pre-commit config, plus test, pre-commit
  and build pipelines on golib-ci.
2026-08-31 22:19:40 +10:00
gitadmin 04e2bf10d9 Initial commit 2026-08-31 06:58:39 +10:00