fix: give the worker a pg Pool and real transactions

The worker ran every job through a single pg Client while BullMQ was
configured with concurrency: 10. A Client is one connection with one
protocol stream and no queueing: ten concurrent jobs interleave on it, and
any BEGIN/COMMIT is shared by all of them, so an unrelated job's failure can
roll back another's work and a rollback can discard a third's committed
intent.

Switched to a Pool, added a small withTransaction(pool, fn) helper that
takes a dedicated connection per transaction, and threaded a Queryable
interface through the services so they accept either a pool or a pooled
client. Both reprocess_artists merge blocks — the artist merge and the
duplicate-album merge — now run inside withTransaction; previously a failure
partway through left artists merged and their tracks unmoved.

integrity.service and cleanup.service get only the constructor type change
here so this commit compiles; their own fixes follow in the next two
commits. cleanup.service's BEGIN/COMMIT-on-a-Pool is therefore still wrong
at this commit and is replaced wholesale by the hard-delete commit.

REVIEW-2026-07-30.md finding 4 (and the concurrency note in finding 3).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kami
2026-07-30 23:56:29 +04:00
parent d0ca479d4f
commit ee43995e96
8 changed files with 186 additions and 100 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
import { Client as PgClient } from 'pg';
import type { Queryable } from './db.js';
import { MusicBrainzClient } from './integrations/musicbrainz.client.js';
import { normalizeForMatching } from './utils/fuzzy-match.js';
@@ -9,7 +9,7 @@ function generateSortName(name: string): string {
}
export class MbSpineWriter {
constructor(private pgClient: PgClient) {}
constructor(private pgClient: Queryable) {}
/**
* Fetch full artist-credit for a recording MBID and write claims.