diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a2a5ef3..ed909851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (**Migration**) Show "abort" button during active bulk migration search - (**Migration**) Keep the migration page open when aborting during the actual migration execution +- (**Migration**) Prevent concurrent requests to the same tracker ### Fixed diff --git a/src/features/migration/MangaMigration.ts b/src/features/migration/MangaMigration.ts index 309379c8..4a2ce229 100644 --- a/src/features/migration/MangaMigration.ts +++ b/src/features/migration/MangaMigration.ts @@ -25,6 +25,9 @@ import type { } from '@/features/chapter/Chapter.types.ts'; import type { GqlMetaHolder } from '@/features/metadata/Metadata.types.ts'; import { getMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts'; +import { Queue } from '@/lib/Queue.ts'; +import type { TrackerIdInfo } from '@/features/tracker/Tracker.types.ts'; +import { assertIsDefined } from '@/base/Asserts.ts'; type MangaToMigrate = NonNullable; type MangaToMigrateTo = NonNullable['manga']; @@ -43,6 +46,20 @@ const performMigrationAction = async (migrateAction: keyof MigrateAction, ...act Promise.all(actions.flatMap((action) => action[migrateAction]())); export class MangaMigration { + private static trackerQueue = new Map(); + + private static getOrCreateQueue(trackerId: TrackerIdInfo['id']): Queue { + if (!MangaMigration.trackerQueue.has(trackerId)) { + MangaMigration.trackerQueue.set(trackerId, new Queue(1)); + } + + const queue = MangaMigration.trackerQueue.get(trackerId); + + assertIsDefined(queue); + + return queue; + } + static async migrate( mangaToMigrate: MangaToMigrate | null | undefined, mangaToMigrateTo: MangaToMigrateTo | null | undefined, @@ -281,12 +298,16 @@ export class MangaMigration { copy: () => trackBindingsToAdd.map( (trackRecord) => - requestManager.bindTracker( - mangaToMigrateTo.id, - trackRecord.trackerId, - trackRecord.remoteId, - trackRecord.private, - ).response, + MangaMigration.getOrCreateQueue(trackRecord.trackerId).enqueue( + String(mangaToMigrate.id), + () => + requestManager.bindTracker( + mangaToMigrateTo.id, + trackRecord.trackerId, + trackRecord.remoteId, + trackRecord.private, + ).response, + ).promise, ), cleanup: () => mode === 'migrate'