Skip to content

Commit 3d66bd4

Browse files
committed
fix(vnext): isolate hostile cleanup promises
1 parent 0ac451c commit 3d66bd4

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

src/vnext/__tests__/relation-catalog-epoch-coordinator.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,32 @@ describe("hostile subscription lifecycle", () => {
13651365
hostileMembership.dispose();
13661366
hostileMembership.dispose();
13671367

1368+
let catchReads = 0;
1369+
const throwingCatchResult = Promise.reject(
1370+
new Error("shadowed catch rejection"),
1371+
);
1372+
Object.defineProperty(throwingCatchResult, "catch", {
1373+
get() {
1374+
catchReads += 1;
1375+
throw new Error("hostile catch getter");
1376+
},
1377+
});
1378+
const throwingCatchOwner = coordinator(
1379+
() => () => throwingCatchResult,
1380+
);
1381+
active(throwingCatchOwner, "scope").dispose();
1382+
1383+
const nonCallableCatchResult = Promise.reject(
1384+
new Error("non-callable catch rejection"),
1385+
);
1386+
Object.defineProperty(nonCallableCatchResult, "catch", {
1387+
value: null,
1388+
});
1389+
const nonCallableCatchOwner = coordinator(
1390+
() => () => nonCallableCatchResult,
1391+
);
1392+
active(nonCallableCatchOwner, "scope").dispose();
1393+
13681394
let thenCalls = 0;
13691395
let reentrantOwner: SqlCatalogEpochCoordinator;
13701396
const reentrantResult = Object.defineProperty(
@@ -1397,6 +1423,7 @@ describe("hostile subscription lifecycle", () => {
13971423
expect(asyncCleanupCalls).toBe(1);
13981424
expect(applyCalls).toBe(1);
13991425
expect(thenReads).toBe(1);
1426+
expect(catchReads).toBe(0);
14001427
expect(thenCalls).toBe(1);
14011428
});
14021429

src/vnext/relation-catalog-epoch-coordinator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,10 @@ function cleanupSubscription(subscription: SubscriptionState): void {
377377
subscription.cleanup = null;
378378
try {
379379
const result = Reflect.apply(cleanup, undefined, []);
380-
void Promise.resolve(result).catch(IGNORE_CLEANUP_REJECTION);
380+
const settlement = new Promise<unknown>((resolve) => {
381+
resolve(result);
382+
});
383+
void settlement.then(undefined, IGNORE_CLEANUP_REJECTION);
381384
} catch {
382385
// Provider cleanup is isolated after state is inert.
383386
}

0 commit comments

Comments
 (0)