'use strict'; const SQLITE_BUSY_RETRY_DELAYS_MS = [ 25, 50, 100, 200, 400, 800, 1600, ]; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function isSqliteBusy(error) { if (!error) return false; if ( error.code === 'SQLITE_BUSY' || error.code === 'SQLITE_LOCKED' ) { return true; } const message = String( error.message || error ).toLowerCase(); return ( message.includes('database is locked') || message.includes('database table is locked') ); } async function withSqliteBusyRetry(label, operation) { let retry = 0; while (true) { try { return await operation(); } catch (error) { if ( !isSqliteBusy(error) || retry >= SQLITE_BUSY_RETRY_DELAYS_MS.length ) { throw error; } const delay = SQLITE_BUSY_RETRY_DELAYS_MS[retry]; retry += 1; console.warn( `[SQLiteRetry] SQLITE_BUSY ${label}; ` + `retry=${retry}/${SQLITE_BUSY_RETRY_DELAYS_MS.length} ` + `delay=${delay}ms` ); await sleep(delay); } } } module.exports = { isSqliteBusy, withSqliteBusyRetry, };