فهرست منبع

fix: prevent doubling transitions

Karol Sójko 1 سال پیش
والد
کامیت
d9ee2c5be2

+ 24 - 3
packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.spec.ts

@@ -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 - 0
packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts

@@ -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
packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.spec.ts

@@ -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 - 0
packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.ts

@@ -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)