diff --git a/packages/revisions/src/Bootstrap/Container.ts b/packages/revisions/src/Bootstrap/Container.ts index fe7d3cc02..9316879c3 100644 --- a/packages/revisions/src/Bootstrap/Container.ts +++ b/packages/revisions/src/Bootstrap/Container.ts @@ -390,6 +390,8 @@ export class ContainerConfigLoader { container.get(TYPES.Revisions_Timer), container.get(TYPES.Revisions_Logger), env.get('MIGRATION_BATCH_SIZE', true) ? +env.get('MIGRATION_BATCH_SIZE', true) : 100, + container.get(TYPES.Revisions_DomainEventPublisher), + container.get(TYPES.Revisions_DomainEventFactory), ), ) container @@ -473,9 +475,6 @@ export class ContainerConfigLoader { container.get( TYPES.Revisions_TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser, ), - container.get(TYPES.Revisions_SQLRevisionRepository), - container.get(TYPES.Revisions_DomainEventPublisher), - container.get(TYPES.Revisions_DomainEventFactory), container.get(TYPES.Revisions_Logger), ), ) diff --git a/packages/revisions/src/Domain/Handler/TransitionRequestedEventHandler.ts b/packages/revisions/src/Domain/Handler/TransitionRequestedEventHandler.ts index 41a8f3a36..3c855f9a8 100644 --- a/packages/revisions/src/Domain/Handler/TransitionRequestedEventHandler.ts +++ b/packages/revisions/src/Domain/Handler/TransitionRequestedEventHandler.ts @@ -1,20 +1,10 @@ -import { - DomainEventHandlerInterface, - DomainEventPublisherInterface, - TransitionRequestedEvent, -} from '@standardnotes/domain-events' +import { DomainEventHandlerInterface, TransitionRequestedEvent } from '@standardnotes/domain-events' import { Logger } from 'winston' import { TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser' -import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface' -import { RevisionRepositoryInterface } from '../Revision/RevisionRepositoryInterface' -import { TransitionStatus, Uuid } from '@standardnotes/domain-core' export class TransitionRequestedEventHandler implements DomainEventHandlerInterface { constructor( private transitionRevisionsFromPrimaryToSecondaryDatabaseForUser: TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser, - private primaryRevisionsRepository: RevisionRepositoryInterface, - private domainEventPublisher: DomainEventPublisherInterface, - private domainEventFactory: DomainEventFactoryInterface, private logger: Logger, ) {} @@ -23,94 +13,13 @@ export class TransitionRequestedEventHandler implements DomainEventHandlerInterf return } - const userUuid = await this.getUserUuidFromEvent(event) - if (!userUuid) { - return - } - - if (await this.isAlreadyMigrated(userUuid)) { - this.logger.info(`[${event.payload.userUuid}] User already migrated.`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Verified, - transitionType: 'revisions', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return - } - - this.logger.info(`[${event.payload.userUuid}] Handling transition requested event`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.InProgress, - transitionType: 'revisions', - transitionTimestamp: event.payload.timestamp, - }), - ) - const result = await this.transitionRevisionsFromPrimaryToSecondaryDatabaseForUser.execute({ userUuid: event.payload.userUuid, + timestamp: event.payload.timestamp, }) if (result.isFailed()) { this.logger.error(`[${event.payload.userUuid}] Failed to transition: ${result.getError()}`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Failed, - transitionType: 'revisions', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return } - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Verified, - transitionType: 'revisions', - transitionTimestamp: event.payload.timestamp, - }), - ) - } - - private async isAlreadyMigrated(userUuid: Uuid): Promise { - const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid) - - if (totalRevisionsCountForUserInPrimary > 0) { - this.logger.info( - `[${userUuid.value}] User has ${totalRevisionsCountForUserInPrimary} revisions in primary database.`, - ) - } - - return totalRevisionsCountForUserInPrimary === 0 - } - - private async getUserUuidFromEvent(event: TransitionRequestedEvent): Promise { - const userUuidOrError = Uuid.create(event.payload.userUuid) - if (userUuidOrError.isFailed()) { - this.logger.error(`[${event.payload.userUuid}] Failed to transition revisions: ${userUuidOrError.getError()}`) - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Failed, - transitionType: 'revisions', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return null - } - - return userUuidOrError.getValue() } } diff --git a/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts b/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts index 2d43b1165..0f55e58a4 100644 --- a/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts +++ b/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts @@ -1,11 +1,13 @@ /* istanbul ignore file */ -import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core' +import { Result, TransitionStatus, UseCaseInterface, Uuid } from '@standardnotes/domain-core' import { TimerInterface } from '@standardnotes/time' import { Logger } from 'winston' import { TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO } from './TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO' import { RevisionRepositoryInterface } from '../../../Revision/RevisionRepositoryInterface' import { TransitionRepositoryInterface } from '../../../Transition/TransitionRepositoryInterface' +import { DomainEventPublisherInterface } from '@standardnotes/domain-events' +import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface' export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements UseCaseInterface { constructor( @@ -15,6 +17,8 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements private timer: TimerInterface, private logger: Logger, private pageSize: number, + private domainEventPublisher: DomainEventPublisherInterface, + private domainEventFactory: DomainEventFactoryInterface, ) {} async execute(dto: TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO): Promise> { @@ -34,12 +38,24 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements } const userUuid = userUuidOrError.getValue() + if (await this.isAlreadyMigrated(userUuid)) { + this.logger.info(`[${userUuid.value}] User already migrated.`) + + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Verified, dto.timestamp) + + return Result.ok() + } + + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.InProgress, dto.timestamp) + const migrationTimeStart = this.timer.getTimestampInMicroseconds() this.logger.info(`[${dto.userUuid}] Migrating revisions`) - const migrationResult = await this.migrateRevisionsForUser(userUuid) + const migrationResult = await this.migrateRevisionsForUser(userUuid, dto.timestamp) if (migrationResult.isFailed()) { + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + return Result.fail(migrationResult.getError()) } @@ -54,11 +70,15 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements await (this.transitionStatusRepository as TransitionRepositoryInterface).setPagingProgress(userUuid.value, 1) await (this.transitionStatusRepository as TransitionRepositoryInterface).setIntegrityProgress(userUuid.value, 1) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + return Result.fail(integrityCheckResult.getError()) } const cleanupResult = await this.deleteRevisionsForUser(userUuid, this.primaryRevisionsRepository) if (cleanupResult.isFailed()) { + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + this.logger.error(`[${dto.userUuid}] Failed to clean up primary database revisions: ${cleanupResult.getError()}`) } @@ -71,10 +91,12 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements `[${dto.userUuid}] Transitioned revisions in ${migrationDurationTimeStructure.hours}h ${migrationDurationTimeStructure.minutes}m ${migrationDurationTimeStructure.seconds}s ${migrationDurationTimeStructure.milliseconds}ms`, ) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Verified, dto.timestamp) + return Result.ok() } - private async migrateRevisionsForUser(userUuid: Uuid): Promise> { + private async migrateRevisionsForUser(userUuid: Uuid, timestamp: number): Promise> { try { const initialPage = await (this.transitionStatusRepository as TransitionRepositoryInterface).getPagingProgress( userUuid.value, @@ -85,6 +107,16 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements const totalRevisionsCountForUser = await this.primaryRevisionsRepository.countByUserUuid(userUuid) const totalPages = Math.ceil(totalRevisionsCountForUser / this.pageSize) for (let currentPage = initialPage; currentPage <= totalPages; currentPage++) { + const isPageInEvery10Percent = currentPage % Math.ceil(totalPages / 10) === 0 + if (isPageInEvery10Percent) { + this.logger.info( + `[${userUuid.value}] Migrating revisions for user: ${Math.round( + (currentPage / totalPages) * 100, + )}% completed`, + ) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.InProgress, timestamp) + } + await (this.transitionStatusRepository as TransitionRepositoryInterface).setPagingProgress( userUuid.value, currentPage, @@ -246,4 +278,27 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements ) } } + + private async updateTransitionStatus(userUuid: Uuid, status: string, timestamp: number): Promise { + await this.domainEventPublisher.publish( + this.domainEventFactory.createTransitionStatusUpdatedEvent({ + userUuid: userUuid.value, + status, + transitionType: 'revisions', + transitionTimestamp: timestamp, + }), + ) + } + + private async isAlreadyMigrated(userUuid: Uuid): Promise { + const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid) + + if (totalRevisionsCountForUserInPrimary > 0) { + this.logger.info( + `[${userUuid.value}] User has ${totalRevisionsCountForUserInPrimary} revisions in primary database.`, + ) + } + + return totalRevisionsCountForUserInPrimary === 0 + } } diff --git a/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO.ts b/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO.ts index 03864549f..d746b3961 100644 --- a/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO.ts +++ b/packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO.ts @@ -1,3 +1,4 @@ export interface TransitionRevisionsFromPrimaryToSecondaryDatabaseForUserDTO { userUuid: string + timestamp: number } diff --git a/packages/syncing-server/src/Bootstrap/Container.ts b/packages/syncing-server/src/Bootstrap/Container.ts index 4e5d86cf4..32c338f9c 100644 --- a/packages/syncing-server/src/Bootstrap/Container.ts +++ b/packages/syncing-server/src/Bootstrap/Container.ts @@ -879,6 +879,8 @@ export class ContainerConfigLoader { container.get(TYPES.Sync_Timer), container.get(TYPES.Sync_Logger), env.get('MIGRATION_BATCH_SIZE', true) ? +env.get('MIGRATION_BATCH_SIZE', true) : 100, + container.get(TYPES.Sync_DomainEventPublisher), + container.get(TYPES.Sync_DomainEventFactory), ), ) container @@ -1049,12 +1051,9 @@ export class ContainerConfigLoader { .bind(TYPES.Sync_TransitionRequestedEventHandler) .toConstantValue( new TransitionRequestedEventHandler( - container.get(TYPES.Sync_SQLItemRepository), container.get( TYPES.Sync_TransitionItemsFromPrimaryToSecondaryDatabaseForUser, ), - container.get(TYPES.Sync_DomainEventPublisher), - container.get(TYPES.Sync_DomainEventFactory), container.get(TYPES.Sync_Logger), ), ) diff --git a/packages/syncing-server/src/Domain/Handler/TransitionRequestedEventHandler.ts b/packages/syncing-server/src/Domain/Handler/TransitionRequestedEventHandler.ts index cc9359715..46e535d71 100644 --- a/packages/syncing-server/src/Domain/Handler/TransitionRequestedEventHandler.ts +++ b/packages/syncing-server/src/Domain/Handler/TransitionRequestedEventHandler.ts @@ -1,21 +1,11 @@ -import { - DomainEventHandlerInterface, - DomainEventPublisherInterface, - TransitionRequestedEvent, -} from '@standardnotes/domain-events' +import { DomainEventHandlerInterface, TransitionRequestedEvent } from '@standardnotes/domain-events' import { Logger } from 'winston' -import { TransitionStatus, Uuid } from '@standardnotes/domain-core' import { TransitionItemsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser' -import { ItemRepositoryInterface } from '../Item/ItemRepositoryInterface' -import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface' export class TransitionRequestedEventHandler implements DomainEventHandlerInterface { constructor( - private primaryItemRepository: ItemRepositoryInterface, private transitionItemsFromPrimaryToSecondaryDatabaseForUser: TransitionItemsFromPrimaryToSecondaryDatabaseForUser, - private domainEventPublisher: DomainEventPublisherInterface, - private domainEventFactory: DomainEventFactoryInterface, private logger: Logger, ) {} @@ -24,95 +14,13 @@ export class TransitionRequestedEventHandler implements DomainEventHandlerInterf return } - const userUuid = await this.getUserUuidFromEvent(event) - if (!userUuid) { - return - } - - if (await this.isAlreadyMigrated(userUuid)) { - this.logger.info(`[${event.payload.userUuid}] User already migrated.`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Verified, - transitionType: 'items', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return - } - - this.logger.info(`[${event.payload.userUuid}] Handling transition requested event`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.InProgress, - transitionType: 'items', - transitionTimestamp: event.payload.timestamp, - }), - ) - const result = await this.transitionItemsFromPrimaryToSecondaryDatabaseForUser.execute({ userUuid: event.payload.userUuid, + timestamp: event.payload.timestamp, }) if (result.isFailed()) { this.logger.error(`[${event.payload.userUuid}] Failed to trigger transition: ${result.getError()}`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Failed, - transitionType: 'items', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return } - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Verified, - transitionType: 'items', - transitionTimestamp: event.payload.timestamp, - }), - ) - } - - private async isAlreadyMigrated(userUuid: Uuid): Promise { - const totalItemsCountForUserInPrimary = await this.primaryItemRepository.countAll({ - userUuid: userUuid.value, - }) - - if (totalItemsCountForUserInPrimary > 0) { - this.logger.info(`[${userUuid.value}] User has ${totalItemsCountForUserInPrimary} items in primary database.`) - } - - return totalItemsCountForUserInPrimary === 0 - } - - private async getUserUuidFromEvent(event: TransitionRequestedEvent): Promise { - const userUuidOrError = Uuid.create(event.payload.userUuid) - if (userUuidOrError.isFailed()) { - this.logger.error(`[${event.payload.userUuid}] Failed to transition items: ${userUuidOrError.getError()}`) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createTransitionStatusUpdatedEvent({ - userUuid: event.payload.userUuid, - status: TransitionStatus.STATUSES.Failed, - transitionType: 'items', - transitionTimestamp: event.payload.timestamp, - }), - ) - - return null - } - - return userUuidOrError.getValue() } } diff --git a/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.ts b/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.ts index 4dfc8a2fe..a01991ac0 100644 --- a/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.ts +++ b/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser.ts @@ -1,12 +1,14 @@ /* istanbul ignore file */ import { TimerInterface } from '@standardnotes/time' -import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core' +import { Result, TransitionStatus, UseCaseInterface, Uuid } from '@standardnotes/domain-core' import { Logger } from 'winston' import { TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO } from './TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO' import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface' import { ItemQuery } from '../../../Item/ItemQuery' import { TransitionRepositoryInterface } from '../../../Transition/TransitionRepositoryInterface' +import { DomainEventPublisherInterface } from '@standardnotes/domain-events' +import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface' export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements UseCaseInterface { constructor( @@ -16,6 +18,8 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use private timer: TimerInterface, private logger: Logger, private pageSize: number, + private domainEventPublisher: DomainEventPublisherInterface, + private domainEventFactory: DomainEventFactoryInterface, ) {} async execute(dto: TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO): Promise> { @@ -35,12 +39,22 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use } const userUuid = userUuidOrError.getValue() + if (await this.isAlreadyMigrated(userUuid)) { + this.logger.info(`[${userUuid.value}] User already migrated.`) + + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Verified, dto.timestamp) + + return Result.ok() + } + const migrationTimeStart = this.timer.getTimestampInMicroseconds() this.logger.info(`[${dto.userUuid}] Migrating items`) - const migrationResult = await this.migrateItemsForUser(userUuid) + const migrationResult = await this.migrateItemsForUser(userUuid, dto.timestamp) if (migrationResult.isFailed()) { + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + return Result.fail(migrationResult.getError()) } @@ -55,11 +69,15 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use await (this.transitionStatusRepository as TransitionRepositoryInterface).setPagingProgress(userUuid.value, 1) await (this.transitionStatusRepository as TransitionRepositoryInterface).setIntegrityProgress(userUuid.value, 1) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + return Result.fail(integrityCheckResult.getError()) } const cleanupResult = await this.deleteItemsForUser(userUuid, this.primaryItemRepository) if (cleanupResult.isFailed()) { + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Failed, dto.timestamp) + this.logger.error(`[${dto.userUuid}] Failed to clean up primary database items: ${cleanupResult.getError()}`) } @@ -72,6 +90,8 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use `[${dto.userUuid}] Transitioned items in ${migrationDurationTimeStructure.hours}h ${migrationDurationTimeStructure.minutes}m ${migrationDurationTimeStructure.seconds}s ${migrationDurationTimeStructure.milliseconds}ms`, ) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.Verified, dto.timestamp) + return Result.ok() } @@ -80,7 +100,7 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use await this.timer.sleep(twoSecondsInMilliseconds) } - private async migrateItemsForUser(userUuid: Uuid): Promise> { + private async migrateItemsForUser(userUuid: Uuid, timestamp: number): Promise> { try { const initialPage = await (this.transitionStatusRepository as TransitionRepositoryInterface).getPagingProgress( userUuid.value, @@ -91,6 +111,14 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use const totalItemsCountForUser = await this.primaryItemRepository.countAll({ userUuid: userUuid.value }) const totalPages = Math.ceil(totalItemsCountForUser / this.pageSize) for (let currentPage = initialPage; currentPage <= totalPages; currentPage++) { + const isPageInEvery10Percent = currentPage % Math.ceil(totalPages / 10) === 0 + if (isPageInEvery10Percent) { + this.logger.info( + `[${userUuid.value}] Migrating items for user: ${Math.round((currentPage / totalPages) * 100)}% completed`, + ) + await this.updateTransitionStatus(userUuid, TransitionStatus.STATUSES.InProgress, timestamp) + } + await (this.transitionStatusRepository as TransitionRepositoryInterface).setPagingProgress( userUuid.value, currentPage, @@ -229,4 +257,27 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use return Result.fail((error as Error).message) } } + + private async updateTransitionStatus(userUuid: Uuid, status: string, timestamp: number): Promise { + await this.domainEventPublisher.publish( + this.domainEventFactory.createTransitionStatusUpdatedEvent({ + userUuid: userUuid.value, + status, + transitionType: 'items', + transitionTimestamp: timestamp, + }), + ) + } + + private async isAlreadyMigrated(userUuid: Uuid): Promise { + const totalItemsCountForUserInPrimary = await this.primaryItemRepository.countAll({ + userUuid: userUuid.value, + }) + + if (totalItemsCountForUserInPrimary > 0) { + this.logger.info(`[${userUuid.value}] User has ${totalItemsCountForUserInPrimary} items in primary database.`) + } + + return totalItemsCountForUserInPrimary === 0 + } } diff --git a/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO.ts b/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO.ts index 3ccd976b0..0ea7f1d3e 100644 --- a/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO.ts +++ b/packages/syncing-server/src/Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO.ts @@ -1,3 +1,4 @@ export interface TransitionItemsFromPrimaryToSecondaryDatabaseForUserDTO { userUuid: string + timestamp: number }