fix: prevent doubling transitions

This commit is contained in:
Karol Sójko
2023-09-04 14:10:37 +02:00
parent eb59902cf7
commit d9ee2c5be2
4 changed files with 70 additions and 6 deletions
@@ -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()
})
})
@@ -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)
@@ -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()
})
})
@@ -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)