fix: resolve duplicate migration timestamps causing ambiguous ordering - #1356
Merged
RUKAYAT-CODER merged 1 commit intoAug 27, 2026
Merged
Conversation
Three migration file pairs shared identical numeric timestamps, making their relative execution order depend on non-deterministic file-load order instead of the timestamp TypeORM uses to sequence migrations: - 1783000000003: add-course-full-text-search / clear-legacy-bcrypt-refresh-tokens - 1790000000000: add-paused-subscription-status / fix-invoice-number-sequence - 1796000000000: add-invoice-tax-columns / reconcile-schema-drift Renumber one migration in each pair to the next unused timestamp and rename its class (TypeORM derives the recorded migration name from the class) so `migrationsTableName` history stays consistent. For the first pair, clear-legacy-bcrypt-refresh-tokens is bumped past the full-text-search migration and the other 1783000000004/1783000000005 DDL migrations, since it performs a data UPDATE that should not race DDL-only migrations. The third pair (1796000000000) wasn't called out in the issue but was found during implementation and fixed the same way for consistency. Adds src/migrations/migration-timestamps.spec.ts, which asserts no two migration files share a timestamp, that every migration class name is suffixed with its file's timestamp, and pins down the three renumbered pairs as a regression test. Closes rinafcode#1196
|
@Rafiat30 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
Thank you for contributing to the project |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1196
Problem
Three pairs of migration files under
src/migrations/shared identical numeric timestamps. TypeORM orders migrations by that timestamp, so within each pair the relative run order was undefined — it depended on filesystem load order rather than an explicit, deterministic sequence:1783000000003-add-course-full-text-search.tsand1783000000003-clear-legacy-bcrypt-refresh-tokens.ts1790000000000-add-paused-subscription-status.tsand1790000000000-fix-invoice-number-sequence.ts1796000000000-add-invoice-tax-columns.tsand1796000000000-reconcile-schema-drift.ts(found while implementing the fix — not called out in the original issue, but the same bug)For the first pair specifically,
clear-legacy-bcrypt-refresh-tokensperforms a dataUPDATEonusers, so it must not race or interleave with the DDL-onlyadd-course-full-text-searchmigration (or the other DDL migrations at1783000000004/1783000000005).Fix
Renumbered one migration in each pair to the next unused timestamp, and renamed its class to match (TypeORM derives the migration's recorded name from the class name, so the two must stay in sync):
clear-legacy-bcrypt-refresh-tokens.ts17830000000031783000000006ClearLegacyBcryptRefreshTokens1783000000006fix-invoice-number-sequence.ts17900000000001790000000001FixInvoiceNumberSequence1790000000001reconcile-schema-drift.ts17960000000001796000000001ReconcileSchemaDrift1796000000001(also updates the explicitnamefield)clear-legacy-bcrypt-refresh-tokenswas bumped to1783000000006(rather than1783000000004, which collides with the existingadd-forum-indexesmigration) so it deterministically runs after the full1783000000003–1783000000005DDL block instead of being sandwiched between DDL migrations.The other file in each pair (
add-course-full-text-search,add-paused-subscription-status,add-invoice-tax-columns) is unchanged.No other files reference the old class names or timestamps (
add-course-full-text-searchis mentioned insrc/search/search.service.ts, but that file kept its original timestamp, so the reference is still correct).Files changed
Renamed (content + class name updated):
src/migrations/1783000000003-clear-legacy-bcrypt-refresh-tokens.ts→src/migrations/1783000000006-clear-legacy-bcrypt-refresh-tokens.tssrc/migrations/1790000000000-fix-invoice-number-sequence.ts→src/migrations/1790000000001-fix-invoice-number-sequence.tssrc/migrations/1796000000000-reconcile-schema-drift.ts→src/migrations/1796000000001-reconcile-schema-drift.tsNew:
src/migrations/migration-timestamps.spec.ts— test file (see below)Tests added
src/migrations/migration-timestamps.spec.ts, following the existing filesystem-scanning spec pattern used elsewhere in the repo (e.g.src/monitoring/prometheus-rules.spec.ts):src/migrations/matching the digit-prefix convention TypeORM'smigrationsglob uses (src/migrations/[0-9]*).namefield, it matches the class name.clear-legacy-bcrypt-refresh-tokens's timestamp is greater thanadd-course-full-text-search's (the ordering that matters per the issue).How to test
npx jest src/migrations/migration-timestamps.spec.ts node scripts/validate-migrations.js # existing CI migration check, confirms it still passesBoth pass locally. Also verified:
grep'd the repo for the old class names/timestamps to confirm nothing else references them.git mvwas used so the renames are tracked as renames, not delete+add.npx tsc --noEmitshows the same pre-existing, unrelated errors intest/*.e2e-spec.tson this branch as onmain).