@@ -3,6 +3,8 @@ const configModule = require('./config');
33const fs = require ( 'fs' ) ;
44const path = require ( 'path' ) ;
55
6+ const sleep = ms => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
7+
68const { parseMigrationMode } = configModule ;
79const baseConfig = { ...configModule } ;
810
@@ -236,6 +238,41 @@ class MigrationManager {
236238 const batchSize = this . config . BATCH_SIZE ;
237239 let processed = 0 ;
238240 let skipped = 0 ;
241+ const rawRetryAttempts = Number ( this . config . TRANSACTION_RETRY_ATTEMPTS ) ;
242+ const retryAttempts = Number . isFinite ( rawRetryAttempts ) && rawRetryAttempts > 0
243+ ? Math . floor ( rawRetryAttempts )
244+ : 0 ;
245+ const rawRetryDelayMs = Number ( this . config . TRANSACTION_RETRY_DELAY_MS ) ;
246+ const retryDelayMs = Number . isFinite ( rawRetryDelayMs ) && rawRetryDelayMs > 0
247+ ? Math . floor ( rawRetryDelayMs )
248+ : 0 ;
249+ const shouldRetryTransactionStart = error =>
250+ this . config . USE_TRANSACTIONS &&
251+ error instanceof Prisma . PrismaClientKnownRequestError &&
252+ error . code === 'P2028' ;
253+ const executeBatch = async ( batch , attempt = 0 ) => {
254+ const uniqueTracker = new Map ( ) ;
255+
256+ try {
257+ if ( this . config . USE_TRANSACTIONS ) {
258+ return await this . prisma . $transaction ( tx => processFn ( batch , tx , uniqueTracker ) ) ;
259+ }
260+ return await processFn ( batch , this . prisma , uniqueTracker ) ;
261+ } catch ( error ) {
262+ if ( attempt < retryAttempts && shouldRetryTransactionStart ( error ) ) {
263+ const nextAttempt = attempt + 1 ;
264+ const waitMs = retryDelayMs ;
265+ const waitSeconds = Math . round ( waitMs / 1000 ) || 0 ;
266+ this . logger . warn ( `Unable to start transaction for batch (P2028). Retrying attempt ${ nextAttempt } of ${ retryAttempts } in ${ waitSeconds } s.` ) ;
267+ if ( waitMs > 0 ) {
268+ await sleep ( waitMs ) ;
269+ }
270+ return executeBatch ( batch , nextAttempt ) ;
271+ }
272+
273+ throw error ;
274+ }
275+ } ;
239276
240277 // Create batches
241278 const batches = [ ] ;
@@ -249,15 +286,7 @@ class MigrationManager {
249286
250287 for ( let i = 0 ; i < batches . length ; i += concurrencyLimit ) {
251288 const batchGroup = batches . slice ( i , i + concurrencyLimit ) ;
252- const batchPromises = batchGroup . map ( batch => {
253- const uniqueTracker = new Map ( ) ;
254-
255- if ( this . config . USE_TRANSACTIONS ) {
256- return this . prisma . $transaction ( tx => processFn ( batch , tx , uniqueTracker ) ) ;
257- } else {
258- return processFn ( batch , this . prisma , uniqueTracker ) ;
259- }
260- } ) ;
289+ const batchPromises = batchGroup . map ( batch => executeBatch ( batch ) ) ;
261290
262291 const batchResults = await Promise . all ( batchPromises ) ;
263292 results . push ( ...batchResults ) ;
0 commit comments