From e0b4b369dc23e539aa061f97a28f9241263293c0 Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 14 Jun 2020 00:35:53 +0200 Subject: [PATCH] transaction handling fixes --- src/services/backup.js | 2 +- src/services/repository.js | 6 +----- src/services/sql.js | 33 ++++++++++++++++++--------------- src/services/sync.js | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/services/backup.js b/src/services/backup.js index 32ae99754..fe0b009ed 100644 --- a/src/services/backup.js +++ b/src/services/backup.js @@ -47,7 +47,7 @@ async function copyFile(backupFile) { for (; attemptCount < COPY_ATTEMPT_COUNT && !success; attemptCount++) { try { - await sql.executeNoWrap(`VACUUM INTO '${backupFile}'`); + await sql.executeWithoutTransaction(`VACUUM INTO '${backupFile}'`); success = true; } catch (e) { diff --git a/src/services/repository.js b/src/services/repository.js index 75fba38c5..399f07b5e 100644 --- a/src/services/repository.js +++ b/src/services/repository.js @@ -140,10 +140,6 @@ async function updateEntity(entity) { await eventService.emit(entity.isDeleted ? eventService.ENTITY_DELETED : eventService.ENTITY_CHANGED, eventPayload); } } - - if (entity.afterSaving) { - await entity.afterSaving(); - } }); } @@ -159,4 +155,4 @@ module.exports = { getOption, updateEntity, setEntityConstructor -}; \ No newline at end of file +}; diff --git a/src/services/sql.js b/src/services/sql.js index dc418757d..c5227e685 100644 --- a/src/services/sql.js +++ b/src/services/sql.js @@ -155,7 +155,7 @@ async function execute(query, params = []) { return await wrap(async db => db.run(query, ...params), query); } -async function executeNoWrap(query, params = []) { +async function executeWithoutTransaction(query, params = []) { await dbConnection.run(query, ...params); } @@ -222,10 +222,12 @@ async function startTransactionIfNecessary() { await transactionPromise; } - await beginTransaction(); - cls.namespace.set('isInTransaction', true); + // first set semaphore (atomic operation and only then start transaction transactionActive = true; transactionPromise = new Promise(res => transactionPromiseResolve = res); + cls.namespace.set('isInTransaction', true); + + await beginTransaction(); } async function transactional(func) { @@ -234,7 +236,7 @@ async function transactional(func) { return await func(); } - cls.namespace.set('isTransactional', true); // we will need a transaction if there's a write operation + cls.namespace.set('isTransactional', true); // this signals that transaction will be needed if there's a write operation try { const ret = await func(); @@ -244,26 +246,27 @@ async function transactional(func) { // note that sync rows sent from this action will be sent again by scheduled periodic ping require('./ws.js').sendPingToAllClients(); - - transactionActive = false; - cls.namespace.set('isInTransaction', false); - transactionPromiseResolve(); } return ret; } catch (e) { - if (transactionActive) { + if (cls.namespace.get('isInTransaction')) { await rollback(); - - transactionActive = false; - cls.namespace.set('isInTransaction', false); - // resolving since this is just semaphore for allowing another write transaction to proceed - transactionPromiseResolve(); } throw e; } + finally { + cls.namespace.set('isTransactional', false); + + if (cls.namespace.get('isInTransaction')) { + transactionActive = false; + cls.namespace.set('isInTransaction', false); + // resolving even for rollback since this is just semaphore for allowing another write transaction to proceed + transactionPromiseResolve(); + } + } } module.exports = { @@ -278,7 +281,7 @@ module.exports = { getMap, getColumn, execute, - executeNoWrap, + executeWithoutTransaction, executeMany, executeScript, transactional, diff --git a/src/services/sync.js b/src/services/sync.js index acc2ccd90..8d1425637 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -372,7 +372,7 @@ sqlInit.dbReady.then(async () => { setInterval(cls.wrap(sync), 60000); // kickoff initial sync immediately - setTimeout(cls.wrap(sync), 1000); + setTimeout(cls.wrap(sync), 3000); setInterval(cls.wrap(updatePushStats), 1000); });