Cap UserEdit edits to fix 16 MB limit (do NOT merge until after v3)#4327
Cap UserEdit edits to fix 16 MB limit (do NOT merge until after v3)#4327imnasnainaec wants to merge 1 commit into
Conversation
Replace full-document UserEdit writes with targeted atomic updates and cap the edits array at the most recent 250 entries via $push + $slice, so goal/step writes can no longer fail once a document nears MongoDB's 16 MB limit. Add database/trim-user-edits.js, a one-shot mongosh script to trim existing oversized documents in place. Fixes #4320 Co-Authored-By: Claude Fable 5 <[email protected]>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4327 +/- ##
==========================================
+ Coverage 75.96% 76.01% +0.04%
==========================================
Files 305 305
Lines 11384 11366 -18
Branches 1411 1408 -3
==========================================
- Hits 8648 8640 -8
+ Misses 2332 2325 -7
+ Partials 404 401 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Superseded by a rework that will move edits into their own collection (one document per edit) instead of capping the array. |
Caution
DO NOT MERGE until after the v3 release. This PR changes the
UserEditwrite path and includes a data migration that trims production data. It is intentionally held back so it doesn't land in the v3 release; merge only once v3 has shipped and the migration plan below has been agreed on.Resolves #4320
Problem
A
UserEditdocument'seditsarray is unbounded, and every goal/step write loaded the full document and rewrote it withReplaceOneAsync. Once a document neared MongoDB's 16 MB limit, every write failed withWriteError 17419and the user was permanently blocked from recording goal/step progress in that project (observed in production; see #4320).Fix
UserEditRepository.Replaceis removed; goal and step writes now use$push/$seton just the affectededitselement.edits. Appending a new edit uses$push+$slice: -UserEdit.MaxEdits, so the array is atomically trimmed to the most recentMaxEditsentries on every append. Growth is bounded going forward.MaxEdits = 250: production documents that hit the limit held 387–976 edits at 14–16 MB (up to ~40 kB per edit), so 250 keeps worst-case documents around 10 MB. Value is easy to tune if we want to keep more history.Because the capped
$pushproduces a smaller resulting document, deploying this backend also unblocks already-affected users on their next goal write — the migration below is still needed to shrink oversized documents proactively (they slow down reads such asGetProjectUserEdits).Frontend requires no changes: edits are addressed by GUID everywhere; nothing persists an index into the
editsarray.Mongo migration instructions
database/trim-user-edits.jstrims everyUserEditdocument with more than 250 edits down to its most recent 250, in place (documents are never deleted — each user'sworkedProjectsreferences the document_id). Run it once against production (and qa) after this PR is deployed:Back up first — trimmed entries are unrecoverable without a backup:
# full backup via the maintenance pod, or at minimum: mongodump --db=CombineDatabase --collection=UserEditsCollectionRun the script on the database pod:
The script prints each affected document (
_id, project, edit count, size) before trimming and verifies afterward that no document exceeds the cap.Per the precedent of the GUID-subtype migration (Migrate MongoDB GUIDs from subtype 3 to 4 #4179 / Remove one-shot db guid migration script #4209), the script can be removed from the repo in a follow-up once it has been run everywhere.
Testing
dotnet build BackendFramework.sln: 0 warnings, 0 errors.dotnet test Backend.Tests: 1186/1186 passed, including 12 newUserEditRepositoryTestsintegration tests that run the new atomic updates against a real (ephemeral) mongod — append, cap-trim (oldest dropped, newest last), replace-by-guid, step append/overwrite, and false-on-missing cases — plus a controller-level trim test via the mock.npm run fmt-backend: clean.Edit.Modified; the new$push/$setupdates preserve that (the goal history UI displays it).Notes for reviewers
Replacehad no callers outsideUserEditService, so it was removed fromIUserEditRepository, the repository, and the mock rather than left as dead code that reintroduces the full-document-rewrite pattern.Edit.changesblob is still unbounded (a single huge edit could in theory exceed limits on its own); trimming what's stored per edit and/or moving edits to their own collection remain the longer-term options discussed in UserEdit document can exceed MongoDB's 16 MB limit, permanently blocking goal/step writes #4320.This change is