From 1f1024c90c66cb9213b9244afc2e2740966d6ebe Mon Sep 17 00:00:00 2001 From: Kifungo A <45813955+adkif@users.noreply.github.com> Date: Mon, 2 Oct 2023 15:06:31 +0000 Subject: [PATCH] fix: SQLite Busy - Locked (#6918) * fix: increase the connection pool size to allow more concurrent connections to the SQLite database. * fix: remove .then() and use async/await * fix: remove .then() and use async/await * fix: use transaction instead of workaround/trick * fix: remove unnecessary console.log(...) * fix: set max pool to 1 for sqlite3 database --- apps/desktop-timer/src/app/app.component.ts | 132 +++++++++--------- .../src/lib/desktop-timer-activity.ts | 86 ++++-------- .../desktop-libs/src/lib/desktop-wakatime.ts | 31 ++-- .../lib/offline/databases/sqlite-provider.ts | 4 +- 4 files changed, 115 insertions(+), 138 deletions(-) diff --git a/apps/desktop-timer/src/app/app.component.ts b/apps/desktop-timer/src/app/app.component.ts index 979f1ff3021..07fa1a98ac9 100644 --- a/apps/desktop-timer/src/app/app.component.ts +++ b/apps/desktop-timer/src/app/app.component.ts @@ -74,90 +74,88 @@ export class AppComponent implements OnInit, AfterViewInit { ngAfterViewInit(): void { this.electronService.ipcRenderer.on('collect_data', (event, arg) => - this._ngZone.run(() => { - this.appService - .collectEvents(arg.tpURL, arg.tp, arg.start, arg.end) - .then((res) => { - event.sender.send('data_push_activity', { - timerId: arg.timerId, - windowEvent: res, - type: 'APP', - }); - }); + this._ngZone.run(async () => { + const res = await this.appService.collectEvents( + arg.tpURL, + arg.tp, + arg.start, + arg.end + ); + event.sender.send('data_push_activity', { + timerId: arg.timerId, + windowEvent: res, + type: 'APP', + }); }) ); this.electronService.ipcRenderer.on('collect_afk', (event, arg) => - this._ngZone.run(() => { - this.appService - .collectAfk(arg.tpURL, arg.tp, arg.start, arg.end) - .then((res) => { - event.sender.send('data_push_activity', { - timerId: arg.timerId, - windowEvent: res, - type: 'AFK', - }); - }); + this._ngZone.run(async () => { + const res = await this.appService.collectAfk( + arg.tpURL, + arg.tp, + arg.start, + arg.end + ); + event.sender.send('data_push_activity', { + timerId: arg.timerId, + windowEvent: res, + type: 'AFK', + }); }) ); this.electronService.ipcRenderer.on( 'collect_chrome_activities', (event, arg) => - this._ngZone.run(() => { - this.appService - .collectChromeActivityFromAW( + this._ngZone.run(async () => { + const res = + await this.appService.collectChromeActivityFromAW( arg.tpURL, arg.start, arg.end - ) - .then((res) => { - event.sender.send('data_push_activity', { - timerId: arg.timerId, - windowEvent: res, - type: 'URL', - }); - }); + ); + event.sender.send('data_push_activity', { + timerId: arg.timerId, + windowEvent: res, + type: 'URL', + }); }) ); this.electronService.ipcRenderer.on( 'collect_firefox_activities', (event, arg) => - this._ngZone.run(() => { - this.appService - .collectFirefoxActivityFromAw( + this._ngZone.run(async () => { + const res = + await this.appService.collectFirefoxActivityFromAw( arg.tpURL, arg.start, arg.end - ) - .then((res) => { - event.sender.send('data_push_activity', { - timerId: arg.timerId, - windowEvent: res, - type: 'URL', - }); - }); + ); + event.sender.send('data_push_activity', { + timerId: arg.timerId, + windowEvent: res, + type: 'URL', + }); }) ); this.electronService.ipcRenderer.on('server_ping', (event, arg) => this._ngZone.run(() => { - const pingHost = setInterval(() => { - this.appService - .pingServer(arg) - .then((res) => { - console.log('Server Found'); + const pingHost = setInterval(async () => { + try { + await this.appService.pingServer(arg); + console.log('Server Found'); + event.sender.send('server_is_ready'); + clearInterval(pingHost); + } catch (error) { + console.log('ping status result', error.status); + if (this.store.userId) { event.sender.send('server_is_ready'); clearInterval(pingHost); - }) - .catch((e) => { - console.log('ping status result', e.status); - if (this.store.userId) { - event.sender.send('server_is_ready'); - clearInterval(pingHost); - } - }); + } + } }, 1000); }) ); @@ -166,21 +164,19 @@ export class AppComponent implements OnInit, AfterViewInit { 'server_ping_restart', (event, arg) => this._ngZone.run(() => { - const pingHost = setInterval(() => { - this.appService - .pingServer(arg) - .then((res) => { - console.log('server found'); + const pingHost = setInterval(async() => { + try { + await this.appService.pingServer(arg); + console.log('Server Found'); + event.sender.send('server_already_start'); + clearInterval(pingHost); + } catch (error) { + console.log('ping status result', error.status); + if (this.store.userId) { event.sender.send('server_already_start'); clearInterval(pingHost); - }) - .catch((e) => { - console.log('ping status result', e.status); - if (this.store.userId) { - event.sender.send('server_already_start'); - clearInterval(pingHost); - } - }); + } + } }, 3000); }) ); diff --git a/packages/desktop-libs/src/lib/desktop-timer-activity.ts b/packages/desktop-libs/src/lib/desktop-timer-activity.ts index a9f40ccabfb..f83ab41d6ce 100644 --- a/packages/desktop-libs/src/lib/desktop-timer-activity.ts +++ b/packages/desktop-libs/src/lib/desktop-timer-activity.ts @@ -13,31 +13,19 @@ export const TimerData = { await timerService.update(timer); }, insertWindowEvent: async (knex: Knex, query, retry = 0) => { - try { - await knex('window-events') - .insert(query) - .onConflict('eventId') - .merge(['duration', 'data', 'updated_at', 'type']); - } catch (error) { - if ( - error.message - .toLowerCase() - .indexOf( - 'Knex: Timeout acquiring a connection'.toLowerCase() - ) > -1 - ) { - if (retry < 3) { - await TimerData.wait(3000); - return await TimerData.insertWindowEvent( - knex, - query, - retry + 1 - ); - } + await knex.transaction(async (trx: Knex.Transaction) => { + try { + await trx('window-events') + .insert(query) + .onConflict('eventId') + .merge(['duration', 'data', 'updated_at', 'type']); + await trx.commit(); + } catch (error) { + await trx.rollback(); + console.log('error on insert window-events', error); + throw error; } - console.log('error on insert window-events', error); - throw error; - } + }); }, updateWindowEventUpload: async (knex, data) => { return await knex('window-events') @@ -81,38 +69,26 @@ export const TimerData = { }); }, insertAfkEvent: async (knex: Knex, query, retry = 0) => { - try { - await knex('afk-events') - .insert(query) - .onConflict('eventId') - .merge([ - 'duration', - 'timerId', - 'data', - 'updated_at', - 'timeSlotId', - 'timeSheetId' - ]); - } catch (error) { - if ( - error.message - .toLowerCase() - .indexOf( - 'Knex: Timeout acquiring a connection'.toLowerCase() - ) > -1 - ) { - if (retry < 3) { - await TimerData.wait(3000); - return await TimerData.insertAfkEvent( - knex, - query, - retry + 1 - ); - } + await knex.transaction(async (trx: Knex.Transaction) => { + try { + await knex('afk-events') + .insert(query) + .onConflict('eventId') + .merge([ + 'duration', + 'timerId', + 'data', + 'updated_at', + 'timeSlotId', + 'timeSheetId', + ]); + await trx.commit(); + } catch (error) { + await trx.rollback(); + console.log('error on insert afk-events', error); + throw error; } - console.log('error on insert afk-events', error); - throw error; - } + }); }, getLastTimer: async (knex, appInfo) => { return await timerService.findLastOne(); diff --git a/packages/desktop-libs/src/lib/desktop-wakatime.ts b/packages/desktop-libs/src/lib/desktop-wakatime.ts index a4609599594..672f804322f 100644 --- a/packages/desktop-libs/src/lib/desktop-wakatime.ts +++ b/packages/desktop-libs/src/lib/desktop-wakatime.ts @@ -1,17 +1,22 @@ export const metaData = { - getActivity: (knex, date) => { - return knex - .select('*') - .from('heartbeats') - .whereBetween('time', [date.end, date.start]) - .then((res) => res) - .catch((error) => console.log(error)); + getActivity: async (knex, date) => { + try { + return await knex + .select('*') + .from('heartbeats') + .whereBetween('time', [date.end, date.start]); + } catch (error) { + console.error(error); + } }, - removeActivity: (knex, data) => { - return knex('heartbeats') - .whereIn('id', data.idsWakatime) - .del() - .then((res) => res) - .catch((error) => console.log(error)); + + removeActivity: async (knex, data) => { + try { + return await knex('heartbeats') + .whereIn('id', data.idsWakatime) + .del(); + } catch (error) { + console.error(error); + } }, }; diff --git a/packages/desktop-libs/src/lib/offline/databases/sqlite-provider.ts b/packages/desktop-libs/src/lib/offline/databases/sqlite-provider.ts index 7e16d3dfa48..b93899e4dea 100644 --- a/packages/desktop-libs/src/lib/offline/databases/sqlite-provider.ts +++ b/packages/desktop-libs/src/lib/offline/databases/sqlite-provider.ts @@ -22,8 +22,8 @@ export class SqliteProvider implements IServerLessProvider { timezone: 'utc' }, pool: { - min: 2, - max: 5, + min: 0, + max: 1, createTimeoutMillis: 3000, acquireTimeoutMillis: 60 * 1000 * 2, idleTimeoutMillis: 30000,