feat(hydra): add a one-off table rewrite Job #71
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/hydra-vacuum-maintenance"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this does
This adds one file that an operator runs by hand:
manifests/maintenance/job-hydra-vacuum-full.yaml. It rewrites thehydra_oauth2_accesstable and gives the disk back to the filesystem.Why
The hourly
hydra janitorCronJob deletes expired tokens. A DELETE keeps thepages in the table for PostgreSQL to use again. It does not shrink the file on
disk. The janitor's own header comment already says this.
Measured on 2026-09-07 in the
hydradatabase:hydra_oauth2_accessholds 541 MB.The cluster is CloudNativePG
postgresin namespacecnpg. The PGDATA volumeis 10Gi with 9.2G free.
pg_repackis not in the image and is not inshared_preload_libraries. It isrejected.
VACUUM FULLis the remaining tool.The Job refuses to run today
The node agent DaemonSet still runs an old image. It asks for a new token on
every call, about 14,000 tokens each hour. Those rows are live, not dead.
A
VACUUM FULLtoday would reclaim almost nothing.seanfarm pull request 400 rolls that DaemonSet to a release that keeps its
token. That roll must land first.
Until then the
precheckinit container stops the run. It readsn_live_tupand exits non-zero when the count is above
MAX_LIVE_ROWS(50,000). The guardis the reason this Job is safe to keep in the repository.
The guard also fails closed. An empty or non-numeric row count refuses the run.
A test on that value inside an
ifwould hide the error and let the rewrite rununguarded.
The lock
VACUUM FULLtakes an ACCESS EXCLUSIVE lock. Hydra writes this table on everytoken grant. Every grant waits while the rewrite runs.
The Job sets
lock_timeoutto 10 seconds. It fails fast instead of queueingbehind the writers and stalling every later grant. It sets the bound twice: once
with
PGOPTIONSwhen the session opens, and once withSET lock_timeout.Argo CD does not sync this
manifests/maintenance/is not referenced by any Argo CD Application. The twoApplications in
apps/readmanifests/stackandmanifests/usersonly. Thereare no kustomization files in this repository.
This matters. A Job under
manifests/stack/would be re-created and re-run byArgo CD after its TTL, with no operator watching.
Shape of the Job
backoffLimit: 0. Never retry a table rewrite on its own.restartPolicy: Never.activeDeadlineSeconds: 900.ttlSecondsAfterFinished: 86400.automountServiceAccountToken: false. The Job speaks to PostgreSQL only.runAsNonRoot,uid and gid 65534,
fsGroup65534,RuntimeDefaultseccomp,allowPrivilegeEscalation: false,readOnlyRootFilesystem: true, and allcapabilities dropped. Both containers carry it.
same digest the CNPG bootstrap uses.
secretKeyRefonhydra-secrets, keyDSN, and nothingelse.
envFromis not used, because the Job needs one key only. No connectionstring is spelled out in the file.
Tests
New
tests/hydra-vacuum-contract.sh, wired intotests/check.sh. It followsthe style of
tests/hydra-janitor-contract.sh.The guard failed first on the missing manifest. Eleven separate mutations were
then tested. Each one made the guard fail:
lock_timeout.envFrom.manifests/stack/.MAX_LIVE_ROWScomparison.readOnlyRootFilesystemon the second container.postgres://connection string.backoffLimitto 3.manifests/stack/as well.manifests/maintenance.bash tests/check.shpasses. The Job also passeskubectl apply --dry-run=client. Nothing was applied to the cluster.README
New section "Hydra table maintenance (one-off, operator)". It gives the
read-only pre-check queries, the
kubectl -n ory create -f ...command, how towatch the run, and the one-day TTL.
It states plainly that the lock stalls every token grant. Expect about 5 to 20
seconds when the live rows are below 30,000. Expect 1 to 3 minutes if the table
is still large.
It says to stay away from the busy times. The CNPG scheduled backup runs every
six hours, at 00:00, 06:00, 12:00 and 18:00 UTC. The janitor runs at minute 23.
https://claude.ai/code/session_015dkyh6itUFos3aSZnomh2w
c5e414088e120625ee6b120625ee6b14c89d31eb14c89d31ebcdf93f2a57