Handle race when two groups match up with same target
Some checks are pending
E2E Tests / e2e (push) Waiting to run
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run

GroupMatch has unique constraints on both alphaGroupId and bravoGroupId
(a group can only be in one match). If two managers click MATCH_UP at
nearly the same moment against overlapping groups, the second INSERT
trips SQLITE_CONSTRAINT_UNIQUE and bubbles up as a 500.

Translate that error into a SendouQError inside SQMatchRepository.create
so the q/looking action's existing SendouQError catch treats it like
any other stale-state error and returns null, which causes the loader
to re-run and the user sees the fresh state instead of an error page.
This commit is contained in:
Kalle
2026-04-24 21:44:33 +03:00
parent f216423089
commit 9f38719fc3

View File

@@ -16,8 +16,10 @@ import {
concatUserSubmittedImagePrefix,
tournamentLogoWithDefault,
} from "~/utils/kysely.server";
import { errorIsSqliteUniqueConstraintFailure } from "~/utils/sql";
import type { Unpacked } from "~/utils/types";
import { FULL_GROUP_SIZE } from "../sendouq/q-constants";
import { SendouQError } from "../sendouq/q-utils.server";
import * as SQGroupRepository from "../sendouq/SQGroupRepository.server";
import { MATCHES_PER_SEASONS_PAGE } from "../user-page/user-page-constants";
import { compareMatchToReportedScores } from "./core/match.server";
@@ -410,7 +412,15 @@ export function create({
memento: JSON.stringify(memento),
})
.returningAll()
.executeTakeFirstOrThrow();
.executeTakeFirstOrThrow()
.catch((error) => {
// race: another manager matched one of the two groups first, tripping the
// unique constraint on GroupMatch.alphaGroupId / bravoGroupId
if (errorIsSqliteUniqueConstraintFailure(error)) {
throw new SendouQError("Group is already in a match");
}
throw error;
});
await trx
.insertInto("GroupMatchMap")