mirror of
https://github.com/standardnotes/server
synced 2026-07-14 00:01:54 -04:00
fix: prevent doubling transitions
This commit is contained in:
+24
-3
@@ -131,7 +131,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -344,7 +344,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
'Total revisions count for user 00000000-0000-0000-0000-000000000000 in primary database (2) does not match total revisions count in secondary database (1)',
|
||||
)
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -368,7 +368,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('Revision 00000000-0000-0000-0000-000000000001 not found in secondary database')
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -413,4 +413,25 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not migrate revisions if there are no revisions in the primary database', async () => {
|
||||
primaryRevisionRepository.countByUserUuid = jest.fn().mockResolvedValue(0)
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(1)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
expect(primaryRevisionRepository.findByUserUuid).not.toHaveBeenCalled()
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).insert).not.toHaveBeenCalled()
|
||||
expect(primaryRevisionRepository.removeByUserUuid).not.toHaveBeenCalled()
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
+12
@@ -24,6 +24,12 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.logger.info(`Revisions for user ${userUuid.value} are already migrated`)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
const migrationTimeStart = this.timer.getTimestampInMicroseconds()
|
||||
|
||||
this.logger.debug(`Transitioning revisions for user ${userUuid.value}`)
|
||||
@@ -137,6 +143,12 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
await this.timer.sleep(twoSecondsInMilliseconds)
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
|
||||
return totalRevisionsCountForUserInPrimary === 0
|
||||
}
|
||||
|
||||
private async checkIntegrityBetweenPrimaryAndSecondaryDatabase(userUuid: Uuid): Promise<Result<boolean>> {
|
||||
try {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
|
||||
+22
-3
@@ -138,7 +138,7 @@ describe('TransitionItemsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(2)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(3)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledWith({ userUuid: '00000000-0000-0000-0000-000000000000' })
|
||||
expect(primaryItemRepository.findAll).toHaveBeenCalledTimes(4)
|
||||
expect(primaryItemRepository.findAll).toHaveBeenNthCalledWith(1, {
|
||||
@@ -329,7 +329,7 @@ describe('TransitionItemsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
'Total items count for user 00000000-0000-0000-0000-000000000000 in primary database (2) does not match total items count in secondary database (1)',
|
||||
)
|
||||
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(2)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(3)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledWith({ userUuid: '00000000-0000-0000-0000-000000000000' })
|
||||
expect((secondaryItemRepository as ItemRepositoryInterface).countAll).toHaveBeenCalledTimes(1)
|
||||
expect(primaryItemRepository.deleteByUserUuid).not.toHaveBeenCalled()
|
||||
@@ -351,7 +351,7 @@ describe('TransitionItemsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('Item 00000000-0000-0000-0000-000000000001 not found in secondary database')
|
||||
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(2)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(3)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledWith({ userUuid: '00000000-0000-0000-0000-000000000000' })
|
||||
expect((secondaryItemRepository as ItemRepositoryInterface).countAll).toHaveBeenCalledTimes(1)
|
||||
expect(primaryItemRepository.deleteByUserUuid).not.toHaveBeenCalled()
|
||||
@@ -374,4 +374,23 @@ describe('TransitionItemsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect((secondaryItemRepository as ItemRepositoryInterface).deleteByUserUuid).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not migrate items if there are no items in the primary database', async () => {
|
||||
primaryItemRepository.countAll = jest.fn().mockResolvedValue(0)
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledTimes(1)
|
||||
expect(primaryItemRepository.countAll).toHaveBeenCalledWith({ userUuid: '00000000-0000-0000-0000-000000000000' })
|
||||
expect(primaryItemRepository.findAll).not.toHaveBeenCalled()
|
||||
expect((secondaryItemRepository as ItemRepositoryInterface).save).not.toHaveBeenCalled()
|
||||
expect(primaryItemRepository.deleteByUserUuid).not.toHaveBeenCalled()
|
||||
expect((secondaryItemRepository as ItemRepositoryInterface).deleteByUserUuid).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
+12
@@ -25,6 +25,12 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.logger.info(`Items for user ${userUuid.value} are already migrated`)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
const migrationTimeStart = this.timer.getTimestampInMicroseconds()
|
||||
|
||||
const migrationResult = await this.migrateItemsForUser(userUuid)
|
||||
@@ -72,6 +78,12 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalItemsCountForUser = await this.primaryItemRepository.countAll({ userUuid: userUuid.value })
|
||||
|
||||
return totalItemsCountForUser === 0
|
||||
}
|
||||
|
||||
private async allowForSecondaryDatabaseToCatchUp(): Promise<void> {
|
||||
const twoSecondsInMilliseconds = 2_000
|
||||
await this.timer.sleep(twoSecondsInMilliseconds)
|
||||
|
||||
Reference in New Issue
Block a user