Skip to content

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 13:41
· 296 commits to main since this release
fe9fad8

✨ Added

runtime

  • connect({ primary, replicas }) opens one pool per endpoint and probes each replica. A string or a pool is unchanged and does not load that code (D201).
  • Reads on a topology go to an eligible replica. route: "primary" or "replica" forces a read. db.using("primary" | "replica") returns a client with no close and no using. onRoute reports the choice, and a throw from it is ignored. routing.fallback is "primary" or "error". A required replica that is not eligible is OKM1843. An automatic read with fallback: "error" and no eligible replica is OKM1844. A write, transaction, or locking read on a replica scope is OKM1840. A string or pool client serves either route from its one endpoint and has no using. inspect() stays single-endpoint. Routing reasons in inspect() are the M2 dev inspector (D202).
  • routing.select chooses the replica: weighted (the default, smooth weighted round-robin), roundRobin, leastConnections, latencyAware, or a function. A weight of 0 is OKM1120. A saturated replica is skipped on an automatic read. If every healthy replica is saturated, the read uses the primary (fallback:saturated) or OKM1844. route: "replica" still uses a saturated replica. A connection failure retries once with the same strategy (D203).
  • routing.consistency is "session" (the default) or "eventual". A committed write reads pg_current_wal_insert_lsn() before its promise resolves when replicas are configured. That is one extra round trip. Later reads use a replica that has replayed at least that far. The root, for(), unscoped(), using(), and reserve() share that watermark. A failed position read keeps automatic reads on the primary (fallback:position-unknown, or OKM1844) until the next successful read. A primary probe already in flight does not clear that state; only a probe started in the same unknown generation does. route: "replica" and using("replica") are OKM1843 while the position is unknown or no replica satisfies it. Healthy replicas that are behind report fallback:behind (D204).
  • routing.maxLag accepts "5s", "500ms", "2m", "16MB", "512KB", "1GB", and "4096B". A bare number or any other form is OKM1120. A caught-up replica has lag zero. A custom select receives that lag in bytes, or null when it is unknown (D204).

tooling

  • A migrate target that carries primary, replicas, weight, or pool is OKM1845. The command does not resolve that URL.
  • Issues and pull requests follow one GitHub standard: one type: label, at least one area: label, a type(scope): title, and a milestone. A check on the pull request adds the area: labels from changed paths, then enforces it. Dependabot opens grouped weekly chore(deps) updates, labelled, with no issue or milestone required (D206).

docs

  • A reference app in packages/reference-app (private, not published): a multi-tenant project tracker on public entry points, with traits, archive, three generated migrations, a function, views, and the replica topology. CI runs it in the postgres and tarball jobs: use cases with query counts and isolation(), two preview databases at once from the snapshot, a rehearsal on a populated TEMPLATE clone, and read-your-write as the application role. docs/example-app.md describes it (D207).
  • The README covers the 0.5 topology: connect({ primary, replicas }), automatic read routing, route, db.using, routing.select, consistency, onRoute, and OKM1840, OKM1843, OKM1844, OKM1845, and OKM1846, plus the reference app as the worked example. The session-watermark cost and the fallback rate under write load are recorded for a primary and two standbys (D209).

♻️ Changed

  • An automatic read uses routing.select instead of the first healthy replica.
  • The session wrote flag is gone. A read after a committed write follows the commit position.

🐛 Fixed

dialects

  • View scratch verification creates the schema's functions before its views, so okm check passes for a view that calls a declared function (D208).
  • archivable() writes the partial unique index predicate the way Postgres prints it, (archived_at IS NULL), so a unique column on an archivable table no longer drifts after every apply. Stored catalogs change once (D208).
  • A function grant names its argument types from oidvectortypes, so EXECUTE on a function with named arguments no longer drifts, and okm doctor and the apply preflight check that grant instead of skipping it (OKM1825) (D208).
  • Grants and default privileges target the schema they are applied to. okm migrate check --provision with roles no longer grants on the target's own objects (D208).

runtime

  • db.views is typed from schema({ views }) on connected, scoped, and routed clients. Each field is the camel-cased column name, typed string | null. Types only (D208).
  • Smooth weighted round-robin clears the current weight of a replica that did not take part in a pick. After that replica is eligible again, a heavier replica keeps the next read (D205).

tooling

  • okm migrate check reads each scratch schema with that schema as the search path. A declared view and a function that takes a schema enum no longer fail with OKM1547 or OKM1020 (D208).
  • okm migrate check with roles keeps default privileges in the scratch schema, so it passes and no longer writes them to the target's public (D208).
  • Roles, grants, and default privileges are left out of the stored catalog hash and the .okm artifact. connect() after an apply with roles no longer fails with OKM1520 when catalogDir is not passed. okm check still verifies them. A catalog without roles hashes as before (D208).
  • okm migrate apply moves a hash stored before D208 to the new hash when it is exactly the old hash of a migration already applied, also when nothing is pending, and prints restamped <migration id>. A protected target needs --allow-protected. Any other hash is left as drift (D208).
  • Upgrade, archivable with a unique column: after upgrading, connect() is OKM1520 and okm check is OKM1510 (OKM1529 creates a unique index). Run okm generate archive_predicate, add -- okm-allow OKM1529: rebuilds the same index above the create unique index concurrently line, then okm migrate apply. okm migrate check still reports OKM1547 at the migration that first created the index, as it did before; see known limits (D208).
  • Upgrade, a database applied with roles: after upgrading, connect() is OKM1520 until okm migrate apply runs once (--allow-protected on a protected target). It prints restamped <migration id> (D208).
  • okm migrate apply on several databases of one cluster at once no longer fails when they create the same managed role. Every apply but the first failed on pg_authid_rolname_index with a raw driver error. CREATE ROLE now ignores a role another session created first, in the step runner and in the snapshot install, and later ALTER ROLE steps still run (D207).
  • isolation() no longer fails with OKM1120 on a schema with a tenant-scoped view. It checks tables only; a view that hides the tenant key is still OKM1820 in okm check (D207).