fix(migrations): sync Migration indexes on boot to enforce unique name#3455
fix(migrations): sync Migration indexes on boot to enforce unique name#3455PierreBrisorgueil merged 2 commits intomasterfrom
Conversation
The Migration collection's unique-on-name index (which backs the atomic claim logic in claimMigration) was only declared on the schema, not actively enforced against existing collections. Deployments whose `migrations` collection was created before the unique: true flag was added kept running without the index, silently allowing duplicate claims and causing the 'should reject duplicate migration names' integration test to fail intermittently on clean boots. Call Migration.syncIndexes() at the start of migrations.run() so the unique index is created (or re-created) before any read/write against the collection. Idempotent and cheap on every boot. Add a unit test asserting the schema declares unique: true on name to guard against accidental regressions. Closes #3454
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 22 minutes and 21 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughAdded a new Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 #3455 +/- ##
==========================================
+ Coverage 85.74% 85.81% +0.06%
==========================================
Files 114 115 +1
Lines 2911 2911
Branches 805 805
==========================================
+ Hits 2496 2498 +2
+ Misses 329 327 -2
Partials 86 86 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Ensures the migrations collection enforces uniqueness on migration name by syncing indexes at startup, preventing duplicate migration claims and restoring the atomicity guarantee relied on by concurrent boot runners.
Changes:
- Add
ensureMigrationIndexes()and call it at the start ofmigrations.run()tosyncIndexes()before any reads/writes. - Export
ensureMigrationIndexes()from the migrations service. - Add a unit test asserting the Migration schema declares
unique: trueonname.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
lib/services/migrations.js |
Sync Migration indexes on boot (via syncIndexes()) to enforce the unique name constraint before claiming/recording migrations. |
modules/core/tests/migrations.unit.tests.js |
Add a unit-level assertion that the name schema path declares unique: true. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/services/migrations.js`:
- Around line 132-134: The helper ensureMigrationIndexes directly accesses
mongoose.model('Migration') and calls Migration.syncIndexes(); move this
datastore access into a repository method (e.g., add a
MigrationRepository.syncIndexes or migrationRepo.ensureIndexes) that performs
the mongoose.model('Migration').syncIndexes() call, then update
ensureMigrationIndexes to call that repository method instead so the service
layer no longer imports/uses Mongoose directly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 040682fd-eeb4-4f26-89db-fb4dc4716e01
📒 Files selected for processing (2)
lib/services/migrations.jsmodules/core/tests/migrations.unit.tests.js
Address CodeRabbit review: the migrations service was directly calling
mongoose.model('Migration') for every read/write, violating the layer
rule that Mongoose imports stay confined to repositories and models.
- Introduce modules/core/repositories/migration.repository.js with
syncIndexes / listExecuted / create / deleteByName primitives.
- Refactor lib/services/migrations.js to delegate all data access to
the repository; the service now only imports the repository and
no longer touches Mongoose directly.
No behavioral change — all 766 tests still pass, coverage thresholds
still met.
Addressed in de6c666 — mongoose access moved into modules/core/repositories/migration.repository.js; CodeRabbit confirmed the fix in its follow-up review.
Summary
Migration.syncIndexes()at the start ofmigrations.run()so the unique-on-nameindex is created/re-created before any read or write against themigrationscollection. Add a unit test asserting the schema declaresunique: trueonname.unique: trueonname, but the index is only built when Mongoose auto-creates it. Deployments whosemigrationscollection was created before the unique flag was added kept running without the index, silently allowing duplicate claims and causing theshould reject duplicate migration namesintegration test to fail on clean boots. This also breaks the atomic claim guarantee used byclaimMigration()to prevent concurrent runners from executing the same migration twice.Scope
lib/services/migrations.js,modules/core/tests/migrations.unit.tests.jsnonelowValidation
npm run lintnpm test(full suite with coverage — 766 tests, 64 suites, all green)Guardrails check
Notes for reviewers
claimMigration()that prevents two concurrent boot runners (e.g. rolling deploys) from executing the same migration twice. Without the index the claim is not actually atomic — this fix closes that gap for collections that pre-date theunique: truedeclaration.syncIndexes()is idempotent and cheap; it runs once per boot inmigrations.run()before anyclaimMigration()/recordMigration()call, so there's no race. Safe on fresh collections (creates the index) and safe on collections that already have it (no-op).Summary by CodeRabbit
Chores
Tests