refs #4823 Added function handler and more

This commit is contained in:
Guillermo Bonet 2023-06-16 13:43:24 +02:00
parent 02cd8124ba
commit 14b29400a4
3 changed files with 106 additions and 93 deletions

View File

@ -6,22 +6,22 @@ import fs from 'fs';
const env = process.env;
const flModels = yml.load(fs.readFileSync('./models/models.yml', 'utf8'));
let cycle = 1;
let cycle = 1, stopSchedule = false;
class Floriday {
async start() {
try {
await utils.checkConfig();
await utils.checkToken();
utils.separator('Init');
await utils.separator('Init');
} catch (err) {
utils.criticalError(err);
utils.handler('critical', err);
}
};
async tryConn() {
while (true)
try {
utils.warning(new Error('Awaiting a response from the database...'));
await utils.handler('warning', new Error('Awaiting a response from the database...'));
await utils.sleep(env.DB_RECON_TIMEOUT);
await checkCon();
await this.schedule();
@ -34,7 +34,7 @@ class Floriday {
const intervalTime = JSON.parse(env.IS_PRODUCTION)
? env.MS_PRODUCTION_SCHEDULE
: env.MS_TEST_SCHEDULE;
while (!this.stopSchedule) {
while (!stopSchedule) {
try {
await this.trunk();
await new Promise(resolve => setTimeout(resolve, intervalTime));
@ -50,26 +50,27 @@ class Floriday {
async trunk() {
try{
for (let model of flModels)
await utils.syncModel(model);
await utils.checkConnections();
utils.separator(`${cycle++} ${(cycle == 2 ? 'Cycle' : 'Cycles')}`);
} catch (err) {
if (['SequelizeConnectionRefusedError', 'SequelizeConnectionError'].includes(err.name))
throw err;
utils.criticalError(err);
for (let model of flModels) {
if (stopSchedule) return;
await utils.syncModel(model);
}
await utils.separator(`${cycle++} ${(cycle == 2 ? 'Cycle' : 'Cycles')}`);
} catch (err) {
if (err?.original?.code === 'ER_SOCKET_UNEXPECTED_CLOSE') throw err;
utils.handler('critical', err);
}
};
async stop() {
try {
this.stopSchedule = false;
stopSchedule = true;
await closeCon();
console.warn(chalk.dim('\nBye, come back soon 👋'))
} catch (err) {
utils.criticalError(err);
utils.handler('critical', err);
}
};
};

View File

@ -19,12 +19,12 @@ console.log(chalk.hex('#06c581')(
))
try {
utils.startSpin('Creating database connection...');
await utils.startSpin('Creating database connection...');
sequelize = await createConn();
await checkCon();
utils.okSpin();
await utils.okSpin();
} catch (err) {
utils.criticalSpin(err);
await utils.criticalSpin(err);
}
// Conf Models
@ -161,13 +161,13 @@ try {
});
*/
} catch (err) {
utils.criticalError(err);
utils.handler('critical', err);
}
try {
const action = JSON.parse(env.FORCE_SYNC) ? { force: true } : { alter: true };
const actionMsg = JSON.parse(env.FORCE_SYNC) ? 'Forcing' : 'Altering';
utils.startSpin(`${actionMsg} models...`);
await utils.startSpin(`${actionMsg} models...`);
await sequelize.sync(action);
/*
@ -177,11 +177,10 @@ try {
// Create procedures
sequelize.query(fs.readFileSync('routines/procedures/offerRefresh.sql', 'utf-8'));
*/
utils.okSpin();
await utils.okSpin();
}
catch (err) {
utils.criticalSpin(err)
await utils.criticalSpin(err)
}
/**
@ -219,13 +218,13 @@ async function checkCon() {
* Close the connection to the database
*/
async function closeCon() {
utils.failSpin(null, true);
utils.startSpin('Closing database connection...');
await utils.failSpin(null, true);
await utils.startSpin('Closing database connection...');
try {
await sequelize.close()
utils.okSpin();
await utils.okSpin();
} catch (err) {
utils.criticalSpin(err);
await utils.criticalSpin(err);
}
}

145
utils.js
View File

@ -10,7 +10,7 @@ import fs from 'fs';
const env = process.env;
const methods = yml.load(fs.readFileSync('./methods.yml', 'utf8'));
const flModels = yml.load(fs.readFileSync('./models/models.yml', 'utf8'));
const arrow = '└─────';
const arrow = '└───────';
let spinner;
/**
@ -21,7 +21,7 @@ let spinner;
*/
export async function checkToken(isForce) {
try {
startSpin(`Checking token...`);
await startSpin(`Checking token...`);
const clientConfigData = await models.config.findOne();
@ -57,9 +57,9 @@ export async function checkToken(isForce) {
});
} else
optionalMsg = 'Using stored token...';
okSpin(optionalMsg);
await okSpin(optionalMsg);
} catch (err) {
failSpin(err);
await await failSpin(err);
}
};
@ -76,7 +76,7 @@ export async function getCurrentToken() {
* Check the floriday data config.
*/
export async function checkConfig() {
startSpin(`Checking config...`);
await startSpin(`Checking config...`);
const excludedEnvVars = ['VSCODE_GIT_ASKPASS_EXTRA_ARGS'];
const requiredEnvVars = Object.keys(env);
@ -84,13 +84,13 @@ export async function checkConfig() {
for (const reqEnvVar of filteredEnvVars)
if (!process.env[reqEnvVar])
failSpin(new Error(`You haven't provided the ${reqEnvVar} environment variable`));
await failSpin(new Error(`You haven't provided the ${reqEnvVar} environment variable`));
const clientConfigData = await models.config.findOne();
if (!clientConfigData)
await updateClientConfig(env.CLIENT_ID, env.CLIENT_SECRET);
okSpin();
await okSpin();
};
/**
@ -125,8 +125,8 @@ export async function updateClientConfig(clientConfig) {
*
* @param {Integer} ms
*/
export function sleep(ms) {
new Promise(resolve => setTimeout(resolve, ms));
export async function sleep(ms) {
await new Promise(resolve => setTimeout(resolve, ms));
};
/**
@ -135,7 +135,7 @@ export function sleep(ms) {
* @param {String} model Supported models (./models/methods.yml)
*/
export async function syncModel(model) {
startSpin(`Syncing ${model}...`);
await startSpin(`Syncing ${model}...`);
try {
const dbSeqNum = await models.sequenceNumber.findOne({ where: { model } })
let curSeqNum = dbSeqNum?.maxSequenceNumber ?? 0, i = 0;
@ -155,21 +155,26 @@ export async function syncModel(model) {
params = params.toString();
}
const res = (await vnRequest('GET', `${env.API_URL}${methods[model].sync.url}${curSeqNum}${params ? `?${params}` : ''}`)).data;
const data = res.results;
curSeqNum = res.maximumSequenceNumber;
const res = (await vnRequest('GET', `${env.API_URL}${methods[model].sync.url}${curSeqNum}${params ? `?${params}` : ''}`));
if (res?.response?.status == 403 && res?.response?.data?.title === 'There are no connected suppliers.') { // Forbidden
await await warnSpin(`Syncing ${model}...`, new Error(res.response.data.title), true);
return;
}
const data = res.data.results;
curSeqNum = res.data.maximumSequenceNumber;
misSeqNum = maxSeqNum - curSeqNum;
await insertModel(model, data);
txtSpin(`Syncing ${i = i + data.length} ${model}, ${misSeqNum} missing...`);
await txtSpin(`Syncing ${i = i + data.length} ${model}, ${misSeqNum} missing...`);
await insertSequenceNumber(model, curSeqNum);
}
await insertSequenceNumber(model, maxSeqNum);
txtSpin((i)
await txtSpin((i)
? `Syncing ${i} ${model}...`
: `Syncing ${model}...`);
okSpin();
await okSpin();
} catch (err) {
failSpin(err);
await await failSpin(err);
}
};
@ -210,12 +215,12 @@ export async function insertModel(model, data) {
*/
export async function checkConnections(){
try {
startSpin('Checking connections...');
await startSpin('Checking connections...');
await createConnections();
await deleteConnections();
if (spinner) okSpin();
if (spinner) await okSpin();
} catch (err) {
failSpin(err);
await failSpin(err);
}
};
@ -669,13 +674,13 @@ export async function createConnections() {
connectionsToPut.push(value.organizationId);
});
if (connectionsToPut.length && !spinner) startSpin('Creating connections...');
if (connectionsToPut.length && !spinner) await startSpin('Creating connections...');
for (let connection of connectionsToPut) {
await vnRequest('PUT', `${env.API_URL}${methods.connections.base.url}${connection}`);
txtSpin(`Creating ${i++} connections, ${connectionsToPut.length - i} missing...`);
await txtSpin(`Creating ${i++} connections, ${connectionsToPut.length - i} missing...`);
}
if (spinner && i) okSpin(`Creating ${i++} connections...`);
if (spinner && i) await okSpin(`Creating ${i++} connections...`);
} catch (err) {
throw err;
}
@ -697,16 +702,16 @@ export async function deleteConnections() {
ghostConnections.push(value.organizationId);
});
if (ghostConnections.length && !spinner) startSpin('Deleting connections...');
if (ghostConnections.length && !spinner) await startSpin('Deleting connections...');
for (let connection of ghostConnections) {
await vnRequest('DELETE', `${env.API_URL}/connections/${connection}`);
txtSpin(`Deleting ${i++} connections, ${ghostConnections.length - i} missing...`)
await txtSpin(`Deleting ${i++} connections, ${ghostConnections.length - i} missing...`)
}
if (spinner && i) okSpin(`Deleting ${i++} connections...`);
if (spinner && i) await okSpin(`Deleting ${i++} connections...`);
} catch (err) {
criticalSpin(err);
await criticalSpin(err);
}
};
@ -737,43 +742,43 @@ export async function vnRequest(method, url, data, headers) {
switch (err.code) {
case 'ECONNRESET': // Client network socket TLS
case 'EAI_AGAIN': // getaddrinfo
warnSpin(null, err, false);
sleep(1000);
await await warnSpin(null, err, false);
await sleep(1000);
break;
case 'ECONNABORTED':
case 'ECONNREFUSED':
case 'ERR_BAD_REQUEST':
switch (err.response.status) {
case 404: // Not found
case 404, 403: // Not found and Forbidden
return err;
case 504:
case 502:
warnSpin(null, err, false);
sleep(1000);
await warnSpin(null, err, false);
await sleep(1000);
break;
case 429: // Too Many Requests
warnSpin(null, err, false);
sleep(60000);
await warnSpin(null, err, false);
await sleep(60000);
break;
case 401: // Unauthorized
warnSpin(null, err, false);
await warnSpin(null, err, false);
await checkToken(true);
headers.Authorization
? headers.Authorization = `Bearer ${await getCurrentToken()}`
: criticalError(err);
: handler('critical', err);;
break;
default:
warnSpin(null, err, false);
sleep(env.MS_RETRY_UNHANDLED_ERROR);
await warnSpin(null, err, false);
await sleep(env.MS_RETRY_UNHANDLED_ERROR);
break;
}
break;
default:
warnSpin(null, err, false);
sleep(env.MS_RETRY_UNHANDLED_ERROR);
await warnSpin(null, err, false);
await sleep(env.MS_RETRY_UNHANDLED_ERROR);
break;
}
startSpin();
await startSpin();
}
}
};
@ -784,7 +789,7 @@ export async function vnRequest(method, url, data, headers) {
* @param {String} msg Text of spinner
* @param {Boolean} isNew Reinstantiate the object
**/
export function startSpin(msg, isKeep) {
export async function startSpin(msg, isKeep) {
if (JSON.parse(env.TIME_STAMPS) && msg)
msg = `${chalk.gray(`[${new moment().format('YYYY-MM-DD hh:mm:ss A')}]`)} ${msg}`;
@ -803,7 +808,7 @@ export function startSpin(msg, isKeep) {
*
* @param {String} msg Text of spinner
**/
export function txtSpin(msg) {
export async function txtSpin(msg) {
if (JSON.parse(env.TIME_STAMPS) && msg)
msg = `${chalk.gray(`[${new moment().format('YYYY-MM-DD hh:mm:ss A')}]`)} ${msg}`;
@ -815,7 +820,7 @@ export function txtSpin(msg) {
*
* @param {String} msg Text of spinner
**/
export function okSpin(msg) {
export async function okSpin(msg) {
if (JSON.parse(env.TIME_STAMPS) && msg)
msg = `${chalk.gray(`[${new moment().format('YYYY-MM-DD hh:mm:ss A')}]`)} ${msg ?? ''}`;
@ -832,7 +837,7 @@ export function okSpin(msg) {
* @param {Error} err Error object
* @param {Boolean} clear Clean the instance
**/
export function warnSpin(msg, err, clear) {
export async function warnSpin(msg, err, clear) {
if (JSON.parse(env.TIME_STAMPS) && msg)
msg = `${chalk.gray(`[${new moment().format('YYYY-MM-DD hh:mm:ss A')}]`)} ${msg}`;
@ -840,7 +845,7 @@ export function warnSpin(msg, err, clear) {
spinner.warn(msg);
if (clear) spinner = null;
}
if (err) warning(err);
if (err) await handler('warning', err);
};
/**
@ -848,7 +853,7 @@ export function warnSpin(msg, err, clear) {
*
* @param {Error} err Error object
**/
export function failSpin(err) {
export async function failSpin(err) {
if (spinner) {
spinner.fail();
spinner = null;
@ -861,12 +866,12 @@ export function failSpin(err) {
*
* @param {Error} err Error object
**/
export function criticalSpin(err) {
export async function criticalSpin(err) {
if (spinner) {
spinner.fail();
spinner = null;
}
criticalError(err);
handler('critical', err);
};
/**
@ -874,28 +879,36 @@ export function criticalSpin(err) {
*
* @param {String} msg String to show
**/
export function separator(msg) {
console.log(chalk.gray(` ──────────────────────── ${msg}`));
export async function separator(msg) {
console.log(chalk.gray(` ──────────────────────── ${msg}`));
};
/**
* Critical error.
* Function to handle error messages.
*
* @param {String} type Type name
* @param {Error} err Error object
**/
export function criticalError(err) {
const msg = `${chalk.red.bold(arrow)} ${chalk.red.bold('[CRITICAL]')}`;
console.log(`${msg} ${chalk.red(err.message)}`);
process.exit();
};
export async function handler(type, err) {
let header = (`${arrow} [${type.toUpperCase()}]`);
let msg = (err.response?.status && err.response?.data?.message)
? `${err.response.status} - ${err.response?.data?.message}`
: err.message;
/**
* Warning.
*
* @param {Error} err
**/
export function warning(err) {
const msg = `${chalk.yellow.bold(arrow)} ${chalk.yellow.bold('[WARNING]')}`;
console.log(`${msg} ${chalk.yellow((err.response?.status && err.response?.data?.message) ?? err.message)}`);
switch (type) {
case 'critical':
header = chalk.red.bold(header);
msg = chalk.red(msg);
break;
case 'warning':
header = chalk.yellow.bold(header);
msg = chalk.yellow(msg);
break;
default:
console.error('Unhandled handler type');
process.exit();
};
console.log(header, msg);
if (type === 'critical') process.exit();
};