refactor: worker threads to import sql dump instead of process

This commit is contained in:
Fabio286 2023-12-02 11:35:20 +01:00
parent 45a695ac0a
commit 03be777c2a
2 changed files with 24 additions and 31 deletions

View File

@ -1,19 +1,14 @@
import { ChildProcess, fork } from 'child_process';
import * as antares from 'common/interfaces/antares'; import * as antares from 'common/interfaces/antares';
import * as workers from 'common/interfaces/workers'; import * as workers from 'common/interfaces/workers';
import { dialog, ipcMain } from 'electron'; import { dialog, ipcMain } from 'electron';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path';
import { Worker } from 'worker_threads'; import { Worker } from 'worker_threads';
import { validateSender } from '../libs/misc/validateSender'; import { validateSender } from '../libs/misc/validateSender';
const isDevelopment = process.env.NODE_ENV !== 'production';
const isFlatpak = process.platform === 'linux' && process.env.DISTRIBUTION === 'flatpak';
export default (connections: {[key: string]: antares.Client}) => { export default (connections: {[key: string]: antares.Client}) => {
let exporter: Worker = null; let exporter: Worker = null;
let importer: ChildProcess = null; let importer: Worker = null;
ipcMain.handle('create-schema', async (event, params) => { ipcMain.handle('create-schema', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
@ -310,25 +305,20 @@ export default (connections: {[key: string]: antares.Client}) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (importer !== null) { if (importer !== null) {
importer.kill(); importer.terminate();
return; return;
} }
return new Promise((resolve/*, reject */) => { return new Promise((resolve/*, reject */) => {
(async () => { (async () => {
if (isFlatpak) {
resolve({ status: 'warning', response: 'Temporarily unavailable on Flatpak' });
return;
}
const dbConfig = await connections[options.uid].getDbConfig(); const dbConfig = await connections[options.uid].getDbConfig();
// Init importer process // Init importer thread
importer = fork(isDevelopment ? './dist/importer.js' : path.resolve(__dirname, './importer.js'), [], { // eslint-disable-next-line @typescript-eslint/ban-ts-comment
execArgv: isDevelopment ? ['--inspect=9224'] : undefined // @ts-ignore
}); importer = new Worker(new URL('../workers/importer', import.meta.url));
importer.send({ importer.postMessage({
type: 'init', type: 'init',
dbConfig, dbConfig,
options options
@ -345,18 +335,18 @@ export default (connections: {[key: string]: antares.Client}) => {
break; break;
case 'end': case 'end':
setTimeout(() => { // Ensures that writing process has finished setTimeout(() => { // Ensures that writing process has finished
importer?.kill(); importer?.terminate();
importer = null; importer = null;
}, 2000); }, 2000);
resolve({ status: 'success', response: payload }); resolve({ status: 'success', response: payload });
break; break;
case 'cancel': case 'cancel':
importer.kill(); importer.terminate();
importer = null; importer = null;
resolve({ status: 'error', response: 'Operation cancelled' }); resolve({ status: 'error', response: 'Operation cancelled' });
break; break;
case 'error': case 'error':
importer.kill(); importer.terminate();
importer = null; importer = null;
resolve({ status: 'error', response: payload }); resolve({ status: 'error', response: payload });
break; break;
@ -387,7 +377,7 @@ export default (connections: {[key: string]: antares.Client}) => {
if (result.response === 1) { if (result.response === 1) {
willAbort = true; willAbort = true;
importer.send({ type: 'cancel' }); importer.postMessage({ type: 'cancel' });
} }
} }

View File

@ -4,6 +4,7 @@ import { ImportOptions } from 'common/interfaces/importer';
import * as log from 'electron-log/main'; import * as log from 'electron-log/main';
import * as mysql from 'mysql2'; import * as mysql from 'mysql2';
import * as pg from 'pg'; import * as pg from 'pg';
import { parentPort } from 'worker_threads';
import { MySQLClient } from '../libs/clients/MySQLClient'; import { MySQLClient } from '../libs/clients/MySQLClient';
import { PostgreSQLClient } from '../libs/clients/PostgreSQLClient'; import { PostgreSQLClient } from '../libs/clients/PostgreSQLClient';
@ -15,14 +16,14 @@ let importer: antares.Importer;
log.transports.file.fileName = 'workers.log'; log.transports.file.fileName = 'workers.log';
log.errorHandler.startCatching(); log.errorHandler.startCatching();
// eslint-disable-next-line @typescript-eslint/no-explicit-any const importHandler = async (data: {
process.on('message', async ({ type, dbConfig, options }: {
type: string; type: string;
dbConfig: mysql.ConnectionOptions & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean } dbConfig: mysql.ConnectionOptions & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean }
| pg.ClientConfig & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean } | pg.ClientConfig & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean }
| { databasePath: string; readonly: boolean }; | { databasePath: string; readonly: boolean };
options: ImportOptions; options: ImportOptions;
}) => { }) => {
const { type, dbConfig, options } = data;
if (type === 'init') { if (type === 'init') {
try { try {
const connection = await ClientsFactory.getClient({ const connection = await ClientsFactory.getClient({
@ -45,7 +46,7 @@ process.on('message', async ({ type, dbConfig, options }: {
importer = new PostgreSQLImporter(pool as unknown as pg.PoolClient, options); importer = new PostgreSQLImporter(pool as unknown as pg.PoolClient, options);
break; break;
default: default:
process.send({ parentPort.postMessage({
type: 'error', type: 'error',
payload: `"${options.type}" importer not aviable` payload: `"${options.type}" importer not aviable`
}); });
@ -54,32 +55,32 @@ process.on('message', async ({ type, dbConfig, options }: {
importer.once('error', err => { importer.once('error', err => {
log.error(err.toString()); log.error(err.toString());
process.send({ parentPort.postMessage({
type: 'error', type: 'error',
payload: err.toString() payload: err.toString()
}); });
}); });
importer.once('end', () => { importer.once('end', () => {
process.send({ parentPort.postMessage({
type: 'end', type: 'end',
payload: { cancelled: importer.isCancelled } payload: { cancelled: importer.isCancelled }
}); });
}); });
importer.once('cancel', () => { importer.once('cancel', () => {
process.send({ type: 'cancel' }); parentPort.postMessage({ type: 'cancel' });
}); });
importer.on('progress', state => { importer.on('progress', state => {
process.send({ parentPort.postMessage({
type: 'import-progress', type: 'import-progress',
payload: state payload: state
}); });
}); });
importer.on('query-error', state => { importer.on('query-error', state => {
process.send({ parentPort.postMessage({
type: 'query-error', type: 'query-error',
payload: state payload: state
}); });
@ -89,7 +90,7 @@ process.on('message', async ({ type, dbConfig, options }: {
} }
catch (err) { catch (err) {
log.error(err.toString()); log.error(err.toString());
process.send({ parentPort.postMessage({
type: 'error', type: 'error',
payload: err.toString() payload: err.toString()
}); });
@ -97,4 +98,6 @@ process.on('message', async ({ type, dbConfig, options }: {
} }
else if (type === 'cancel') else if (type === 'cancel')
importer.cancel(); importer.cancel();
}); };
parentPort.on('message', importHandler);