From 0a96960ae281ac772b4591aab7db9bb5c058acf7 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 24 Feb 2026 17:49:35 +0100 Subject: [PATCH] Fix race condition: deduplicate startMutation calls between autosave and submit Use a shared startPromiseRef so autosave and handleSubmit reuse the same in-flight "create evaluation" promise instead of firing duplicate requests. Co-Authored-By: Claude Opus 4.6 --- .../projects/[projectId]/evaluate/page.tsx | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx b/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx index e6aa174..52959f5 100644 --- a/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx +++ b/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx @@ -42,6 +42,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) { const isSubmittedRef = useRef(false) const isSubmittingRef = useRef(false) const [isSubmitting, setIsSubmitting] = useState(false) + const startPromiseRef = useRef | null>(null) const autosaveTimerRef = useRef | null>(null) const [lastSavedAt, setLastSavedAt] = useState(null) @@ -211,11 +212,17 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) { let evalId = evaluationIdRef.current if (!evalId && myAssignment) { try { - const newEval = await startMutation.mutateAsync({ assignmentId: myAssignment.id }) + // Reuse in-flight start promise to avoid duplicate creation + if (!startPromiseRef.current) { + startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id }) + } + const newEval = await startPromiseRef.current evalId = newEval.id evaluationIdRef.current = evalId } catch { return + } finally { + startPromiseRef.current = null } } if (!evalId) return @@ -297,7 +304,11 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) { let evaluationId = evaluationIdRef.current if (!evaluationId) { - const newEval = await startMutation.mutateAsync({ assignmentId: myAssignment.id }) + if (!startPromiseRef.current) { + startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id }) + } + const newEval = await startPromiseRef.current + startPromiseRef.current = null evaluationId = newEval.id evaluationIdRef.current = evaluationId } @@ -384,9 +395,14 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) { } } + // Reuse in-flight start promise to avoid duplicate creation (e.g. if autosave is mid-flight) let evaluationId = evaluationIdRef.current if (!evaluationId) { - const newEval = await startMutation.mutateAsync({ assignmentId: myAssignment.id }) + if (!startPromiseRef.current) { + startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id }) + } + const newEval = await startPromiseRef.current + startPromiseRef.current = null evaluationId = newEval.id evaluationIdRef.current = evaluationId }