Skip to main content

convex-write-conflicts

Diagnose and permanently fix Convex OCC "Retried due to write conflicts in table X" errors. Use when an Insight or log shows a mutation retrying on the same hot document, especially heartbeat/last-active/counter style writes.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
waynesutton/vibeapps
آخر نشاط في المصدر
٣٠ يونيو ٢٠٢٦ في ٢٠:٢٠
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٤
التفرعات
١٩

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
convex-write-conflicts
description
Diagnose and permanently fix Convex OCC "Retried due to write conflicts in table X" errors. Use when an Insight or log shows a mutation retrying on the same hot document, especially heartbeat/last-active/counter style writes.
# Fixing Convex write conflicts (OCC) Convex uses optimistic concurrency control. A mutation is retried when a document it read or wrote changed during execution. If parallel mutations keep fighting over the same document, you see: > Retried due to write conflicts in table `X` Reference: https://docs.convex.dev/error#1 ## How to read the Insight In the Convex dashboard Insight Breakdown, look at: - Table name in the title (which table is hot) - Conflicting Document ID (one specific row is usually the culprit) - Conflicting Function ("Self" means the mutation conflicts with other calls to itself) - Recent Events timestamps (bursts within the same second = many parallel calls on one row) A single repeated document ID + "Self" + same-second bursts means: too many parallel writes to one hot document. ## Root cause patterns 1. Heartbeat / "last active" timestamp written on every tick. 2. Counters incremented on a single document. 3. A mutation that reads a whole table then writes one row (any insert elsewhere conflicts). 4. A mutation called in a loop from an action. ## The fix (in priority order) 1. Do not write on every call. Gate the write behind a staleness threshold so most calls become read-only no-ops. Read-only calls do not cause write conflicts, and a losing write retry reads the fresh value and early-returns. ```ts const ACTIVITY_UPDATE_THRESHOLD_MS = 2 * 60 * 1000; if (args.lastActiveAt - doc.lastActiveAt >= ACTIVITY_UPDATE_THRESHOLD_MS) { await ctx.db.patch(doc._id, { lastActiveAt: args.lastActiveAt }); } ``` 2. Read only what you need. Use `withIndex` instead of `collect()` over a table, so the read set is small and conflicts are less likely. 3. Spread writes across documents. For true high-throughput counters use the Sharded Counter component instead of one row. 4. De-synchronize clients. Add jitter to client intervals so heartbeats from many tabs/clients do not fire in lockstep: ```ts const intervalMs = 60000 + Math.floor(Math.random() * 15000); ``` 5. Do not call a mutation many times in an action loop. ## Reference fix in this repo `convex/judges.ts` -> `updateActivity` was retrying ~1.6K times on one judge row. Fix: 2-minute server-side staleness threshold (writes become rare no-ops) plus jittered client heartbeat in `src/pages/JudgingInterfacePage.tsx`. This is the canonical pattern for any "last active" or heartbeat write in this codebase. ## Verify the fix 1. Deploy and watch Health -> Insights for the function. The retry count should stop climbing and the warning should clear within a couple hours (Insight data lags). 2. Confirm the feature still works (activity still updates, just less often). 3. Threshold precision is intentionally coarse; activity tracking only needs minute-level accuracy.
عرض على GitHub