Skip to content

Commit 0baec07

Browse files
committed
fix(V2): read home org within caller transaction in ownership guard
resolveHomeOrgUid queried the home org on a separate pooled connection while a cascade-delete write transaction was open. Under CI connection pressure this could block until the 30s test timeout, failing the cascade-delete test and poisoning subsequent specs. Thread options.transaction into the home-org read so it shares the caller's transaction connection, matching the existing parent-record reads in the guard.
1 parent 5d5323f commit 0baec07

1 file changed

Lines changed: 8 additions & 4 deletions

File tree

src/models/v2/staging-v2.model.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class StagingV2 extends Model {
6767
// Resolve the home org once for the whole batch instead of per record.
6868
const needsGuard = Array.isArray(values) &&
6969
values.some((v) => ['UPDATE', 'DELETE'].includes(v?.action) && !v?.is_transfer);
70-
const homeOrgUid = needsGuard ? await StagingV2.resolveHomeOrgUid() : undefined;
70+
const homeOrgUid = needsGuard ? await StagingV2.resolveHomeOrgUid(options) : undefined;
7171
for (const value of values) {
7272
await StagingV2.assertMutationOwnedByHomeOrg(value, options, homeOrgUid);
7373
}
@@ -126,7 +126,7 @@ class StagingV2 extends Model {
126126
});
127127

128128
// Resolve the home org once for all matched staging records.
129-
const homeOrgUid = await StagingV2.resolveHomeOrgUid();
129+
const homeOrgUid = await StagingV2.resolveHomeOrgUid(options);
130130
for (const stagingRecord of stagingRecords) {
131131
await StagingV2.assertMutationOwnedByHomeOrg({
132132
uuid: values.uuid ?? stagingRecord.uuid,
@@ -281,9 +281,13 @@ class StagingV2 extends Model {
281281
return [...new Set(ownerOrgUids)];
282282
}
283283

284-
static async resolveHomeOrgUid() {
284+
static async resolveHomeOrgUid(options) {
285+
// Use the caller's transaction so this read shares the connection of an
286+
// open write transaction (e.g. cascade delete) instead of contending for a
287+
// separate pooled connection, which can deadlock under connection pressure.
285288
const homeOrg = await OrganizationsV2.findOne({
286289
where: { is_home: true },
290+
transaction: options?.transaction,
287291
raw: true,
288292
});
289293
return homeOrg?.org_uid ?? null;
@@ -334,7 +338,7 @@ class StagingV2 extends Model {
334338
// Resolve the home org once per call (reused for every data row and both
335339
// ownership checks below) unless a batch caller already resolved it.
336340
if (homeOrgUid === undefined) {
337-
homeOrgUid = await StagingV2.resolveHomeOrgUid();
341+
homeOrgUid = await StagingV2.resolveHomeOrgUid(options);
338342
}
339343

340344
const parsedData = Array.isArray(values.data)

0 commit comments

Comments
 (0)