Second of two changes for #186; closes it. Each kind of object the
console serializes on now has a family, and every advisory key is built
one way: hashtextextended('<family>:<id>', 0), with a UUID written in
canonical form. db.Lock and db.LockShared (internal/db/locks.go) build
the key and take the lock on a *sql.Tx only, and each family's
statement begins with a name line, so pg_stat_activity and the test
traces show which family a backend waits on.
Families, in the order a transaction takes them: materialization,
domains-registry, fedwiki-workspace, lifecycle, stripe-subscription,
stripe-invoice, stripe-product-sync, desired-state. The lifecycle and
desired-state keys are unchanged byte for byte; the other six change.
Migration 00040 replaces core.assert_rendezvous to look for the new
materialization key (owner, grants, SECURITY DEFINER and search_path
kept; Down restores migration 18's body), and both seeds take the new
key right after BEGIN.
docs/database-locks.md lists the families in a table and writes one
order every path keeps: the materialization lock first, then the
families in table order, then rows. The project lint gains
advisory-lock-site (an advisory lock function named in a Go string or
in SQL or shell code outside the helpers, the test kit's probe, the
migrations that name the rendezvous and the rule's own tests; a seed
taking any other key, or the rendezvous anywhere but first after
BEGIN), pool-lock-site (a core.resource_pools row lock outside
LockResourcePool and LockGrantPool, or a call or method value of those
outside entitlements/tx.go) and lock-families (the doc's table against
the code). The walk covers cmd/, scripts/, internal/, test/ and the
root's Go files, and skips testdata and directories whose name begins
with a dot, as the go tool does. Tests take a family's lock through the
same helpers and probe one with dbtest.TryLock.
Recording a lifecycle request comes in two forms:
RecordLifecycleRequest opens its own transaction on a database or a
pinned connection, and RecordLifecycleRequestInTx runs in the caller's
*sql.Tx, so a connection is never used outside a transaction (which
released the instance lock at once) and does not compile in the second.
The same holds for RecordFirstLifecycleRequest.
docs/production-deployment.md now states the upgrade order for every
upgrade: stop every process of the running release, run migrate up if
migrations run separately, then start the new release; two releases
running at once can build different keys for one lock and share none.
docs/go-conventions.md, docs/testing.md and
docs/building-an-integration.md follow the code. The lint command's
help text names the files the lock rules read. 202 golden lines in 109
files change their statement text.
Deploy: stop every process of the previous release first. Rollback:
stop this release; as the migration user, in one transaction, run
00040's Down section and DELETE FROM goose_db_version_core WHERE
version_id = 40; start the previous release (migrate down rolls back
the last integration stream first). A deployment using console_reader
re-runs scripts/db-reader-role.sql.
Break list: 35 records, 35 CAUGHT. Named without a record: the *sql.Tx
parameters of the helpers and the -InTx forms (a break that passes a
connection does not compile, and the build is the check), and the
comments. Full suite on reset databases: 5727 passed, 16 skipped, none
failed.