diff --git a/src/providers/sqlite3/index.js b/src/providers/sqlite3/index.js index 0196406..7bd0e86 100644 --- a/src/providers/sqlite3/index.js +++ b/src/providers/sqlite3/index.js @@ -6,9 +6,12 @@ */ import Database from 'better-sqlite3'; +import { AsyncLocalStorage } from 'node:async_hooks'; import { logSlowQuery } from '../provider.js'; import { SCHEMA_SCRIPTS } from './schema.js'; +const asyncTxStorage = new AsyncLocalStorage(); + function normalizeParamValue(value) { if (value === undefined || value === null) return null; if (value instanceof Date) { @@ -324,6 +327,7 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { this.pool = this; db.pragma('foreign_keys = ON'); db.pragma('journal_mode = WAL'); + db.pragma('synchronous = NORMAL'); db.pragma('busy_timeout = 5000'); } @@ -366,8 +370,9 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { return runner; }; - if (this.#transactionDepth > 0 || this.db.inTransaction) { - const savepoint = `sp_${++this.#transactionDepth}`; + const activeContext = asyncTxStorage.getStore(); + if (activeContext) { + const savepoint = `sp_${++activeContext.depth}`; this.db.exec(`SAVEPOINT ${savepoint}`); const executor = new BetterSqlite3Executor(this.db, this.storageDir); const runner = bindRunner(executor); @@ -376,8 +381,12 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { .then(() => fn(runner, executor)) .then( (result) => { - this.db.exec(`RELEASE SAVEPOINT ${savepoint}`); - this.#transactionDepth--; + try { + this.db.exec(`RELEASE SAVEPOINT ${savepoint}`); + } catch { + // ignore if outer transaction already rolled back + } + activeContext.depth--; return result; }, (err) => { @@ -387,7 +396,7 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { } catch { // ignore } - this.#transactionDepth--; + activeContext.depth--; throw err; }, ); @@ -399,7 +408,7 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor { try { const executor = new BetterSqlite3Executor(this.db, this.storageDir); const runner = bindRunner(executor); - const result = await fn(runner, executor); + const result = await asyncTxStorage.run({ depth: 0 }, () => fn(runner, executor)); this.db.exec('COMMIT'); return result; } catch (err) {