Fix race condition: deduplicate startMutation calls between autosave and submit
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m5s

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 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 17:49:35 +01:00
parent f3fd9eebee
commit 0a96960ae2

View File

@@ -42,6 +42,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
const isSubmittedRef = useRef(false) const isSubmittedRef = useRef(false)
const isSubmittingRef = useRef(false) const isSubmittingRef = useRef(false)
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const startPromiseRef = useRef<Promise<{ id: string }> | null>(null)
const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null) const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const [lastSavedAt, setLastSavedAt] = useState<Date | null>(null) const [lastSavedAt, setLastSavedAt] = useState<Date | null>(null)
@@ -211,11 +212,17 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
let evalId = evaluationIdRef.current let evalId = evaluationIdRef.current
if (!evalId && myAssignment) { if (!evalId && myAssignment) {
try { 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 evalId = newEval.id
evaluationIdRef.current = evalId evaluationIdRef.current = evalId
} catch { } catch {
return return
} finally {
startPromiseRef.current = null
} }
} }
if (!evalId) return if (!evalId) return
@@ -297,7 +304,11 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
let evaluationId = evaluationIdRef.current let evaluationId = evaluationIdRef.current
if (!evaluationId) { 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 evaluationId = newEval.id
evaluationIdRef.current = evaluationId 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 let evaluationId = evaluationIdRef.current
if (!evaluationId) { 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 evaluationId = newEval.id
evaluationIdRef.current = evaluationId evaluationIdRef.current = evaluationId
} }