fix(polls): canonicalize transaction lock order
This commit is contained in:
1 parent
e9680775f9
commit
de7cc42ddf
4 files changed
+275
-38
No files matched your search
@@ -101,6 +101,28 @@ describe("Content production mutation adapter", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses read committed isolation only for poll mutations", async () => {
|
||||
const pollDeps = dependencies();
|
||||
await pollDeps.adapter.execute(
|
||||
"poll.change",
|
||||
{ action: "delete", id: 7 },
|
||||
mutationContext,
|
||||
);
|
||||
expect(pollDeps.transaction).toHaveBeenCalledWith(expect.any(Function), {
|
||||
isolationLevel: "read committed",
|
||||
});
|
||||
|
||||
const articleDeps = dependencies();
|
||||
await articleDeps.adapter.execute(
|
||||
"article.change",
|
||||
{ action: "update", id: 7 },
|
||||
mutationContext,
|
||||
);
|
||||
expect(articleDeps.transaction).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
it("persists correlated intent and truthful outcome around external storage writes", async () => {
|
||||
const deps = dependencies();
|
||||
await deps.adapter.execute(
|
||||
|
||||
@@ -46,9 +46,14 @@ export const CONTENT_MIXED_OPERATIONS = [
|
||||
|
||||
type TransactionToken = unknown;
|
||||
|
||||
interface ContentTransactionOptions {
|
||||
isolationLevel: "read committed";
|
||||
}
|
||||
|
||||
export interface ContentProductionMutationDependencies {
|
||||
transaction<T>(
|
||||
run: (transaction: TransactionToken) => Promise<T>,
|
||||
options?: ContentTransactionOptions,
|
||||
): Promise<T>;
|
||||
writeAudit(entry: AuditEntry, transaction?: TransactionToken): Promise<void>;
|
||||
executeOperation(
|
||||
@@ -126,6 +131,10 @@ export function createContentProductionMutationAdapter(
|
||||
return {
|
||||
async execute(operation, input, context) {
|
||||
if (includesOperation(CONTENT_DATABASE_OPERATIONS, operation)) {
|
||||
const transactionOptions =
|
||||
operation === "poll.change"
|
||||
? ({ isolationLevel: "read committed" } as const)
|
||||
: undefined;
|
||||
return dependencies.transaction(async (transaction) => {
|
||||
const snapshot = await dependencies.executeOperation(
|
||||
operation,
|
||||
@@ -138,7 +147,7 @@ export function createContentProductionMutationAdapter(
|
||||
transaction,
|
||||
);
|
||||
return snapshot;
|
||||
});
|
||||
}, transactionOptions);
|
||||
}
|
||||
|
||||
await dependencies.writeAudit(auditEntry(operation, context, "intent"));
|
||||
@@ -192,9 +201,9 @@ export function createContentProductionMutationAdapter(
|
||||
|
||||
export const contentProductionMutationAdapter =
|
||||
createContentProductionMutationAdapter({
|
||||
async transaction(run) {
|
||||
async transaction(run, options) {
|
||||
const { db } = await import("@/lib/db");
|
||||
return db.transaction((transaction) => run(transaction));
|
||||
return db.transaction((transaction) => run(transaction), options);
|
||||
},
|
||||
async writeAudit(entry, transaction) {
|
||||
const { logAudit } = await import("@/lib/services/audit");
|
||||
|
||||
Reference in new issue
Block a user