fix(album-metadata-backfill): wrap verifyComplete in tx + SET LOCAL (BS#1022)#1024
Merged
Merged
Conversation
…BS#1022) The dual-count comparison shipped in PR #1020 traded one un-indexed scan for another: count(DISTINCT album_id) WHERE metadata_attempt_at IS NOT NULL walks the opposite partition from the drain partial index (#660), still ~2.6M rows on a heap scan, still tripped the backend's 5s default statement_timeout on the 2026-05-22 prod re-run. Wrap verifyComplete in db.transaction so SET LOCAL statement_timeout actually scopes (postgres-js auto-commits per execute otherwise). Both SET LOCAL and the dual-count SELECT execute through the closure-bound tx handle. Timeout is read from ALBUM_METADATA_BACKFILL_VERIFY_TIMEOUT_MS (default 120000ms), following the operational-knob pattern from BS#995 / BS#1017 on the same job family. Unit tests pin tx-binding by installing a per-call fake-tx with its own execute spy and asserting db.execute is never called inside the transaction body — the real failure mode the previous PR missed wasn't call-ordering, it was the two statements landing on different pooled connections. Closes #1022.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The dual-count fix shipped in #1020 didn't fully resolve the verify-step timeout reported in #1019. On the 2026-05-22 prod re-run, the new
count(DISTINCT album_id) WHERE metadata_attempt_at IS NOT NULLover ~2.6M flowsheet rows still tripped the backend's 5 s defaultstatement_timeout— the partial index from #660 (idx_flowsheet_metadata_drain) covers theIS NULLpartition only, so the verify walks the un-indexed opposite partition.This PR wraps
verifyCompleteindb.transaction+SET LOCAL statement_timeoutso the per-tx timeout actually scopes (postgres-js auto-commits perexecuteotherwise). Both statements run on the closure-boundtxhandle; the timeout is read fromALBUM_METADATA_BACKFILL_VERIFY_TIMEOUT_MS(default120000), following the operational-knob pattern ofBS#995/BS#1017on this job family.Closes #1022.
Background
Fix shape
The transaction wrapper sunsets naturally with D4 (#900) when the inline columns drop and the verify shape changes; the doc comment calls this out so a future "this wrapper looks unnecessary" cleanup doesn't regress the fix.
Env knob
ALBUM_METADATA_BACKFILL_VERIFY_TIMEOUT_MS(default120000/ 120 s) is documented indocs/env-vars.mdalongsideALBUM_PLAYS_REFRESH_TIMEOUT_MS(the closest precedent — same per-statement-timeout pattern on a dedicated path). Non-numeric or non-positive values raise at job startup rather than silently defaulting.Test plan
Unit-level (in
tests/unit/jobs/album-metadata-backfill/job.test.ts):executespy; assert bothSET LOCALand the dual-countSELECTgo throughtx.executeanddb.executeis never called inside the transaction body. The real failure mode the prior PR missed wasn't call-ordering — it was the two statements landing on different pooled connections.SET LOCALis the first transaction statement, dual-countSELECTthe second.120000mswhen env is unset.90000→'90000ms').0).actual >= expectedinvariant preserved (passes on=, passes on>).LEFT JOIN).Local CI gates run against the affected workspace:
npm run test:unit -- tests/unit/jobs/album-metadata-backfill/job.test.ts— 22/22 greennpm run test:unit -- --testPathPatterns='album-metadata-backfill|albumMetadataProjection|flowsheet.getEntriesByRange'— 29/29 greennpm run test:unit -- --testPathPatterns='library-identity-consumer'— 52/52 green (the otherdb.transactionconsumer; no shared-mock changes made)npx eslint jobs/album-metadata-backfill tests/unit/jobs/album-metadata-backfill— 0 errors, 2 pre-existing warningsnpx prettier --check jobs/album-metadata-backfill tests/unit/jobs/album-metadata-backfill docs/env-vars.md— cleannpx tsc --noEmit -p jobs/album-metadata-backfill/tsconfig.json— cleanThe (optional) integration test asserting
current_setting('statement_timeout')mid-transaction was discussed in the review and deferred — happy to add as a follow-up if you want belt-and-suspenders. The unit tests pin the load-bearing behavior (tx-binding + statement ordering + env wiring + invariant).Prod re-run
Held until BS#1011's drain finishes. Expected outcome once unblocked: 0 new INSERTs (idempotent), ANALYZE re-runs, dual-count verify logs
Verification passed: album_metadata=7101 >= expected=7101and exits 0.Alternative considered
Adding a partial index on
flowsheet(album_id) WHERE metadata_attempt_at IS NOT NULLwould also unblock the verify, but the index has no other reader and sunsets with D4. The transaction wrapper is the proportionally-smaller fix with a natural deletion path.