fix: refs #4452 Lost connection with db
gitea/dismuntel/pipeline/pr-main This commit looks good Details
gitea/vn-rfid-printer/pipeline/pr-main This commit looks good Details

This commit is contained in:
Guillermo Bonet 2024-10-29 11:46:58 +01:00
parent c087b0920a
commit 7d6a00ea4c
3 changed files with 45 additions and 70 deletions

View File

@ -34,19 +34,23 @@ Este proyecto es una aplicación backend que utiliza Node.js, Docker, MariaDB y
4. Crea un archivo `.env` en el directorio raíz del proyecto y configura las variables de entorno necesarias:
```env
# DEBUG = 1
# KEEP_TMP_FILES = 1
# DRY_PRINT = 1
DB_HOST = mariadb
DB_PORT = 3306
DB_USER = user
DB_PASSWORD = password
DB_NAME = name
DB_PRINTER_SCHEMA = name
WORKERS = 10
GET_RECORD_DELAY = 4000
PRINTER_TIMEOUT = 1000
PRINTER_PORT = 9100
# DEBUG=1
# KEEP_TMP_FILES=1
# DRY_PRINT=1
DB_HOST=mariadb
DB_PORT=3306
DB_USER=user
DB_PASSWORD=password
DB_NAME=name
DB_PRINTER_SCHEMA=name
WORKERS=10
REPLACE_WORKER_DELAY=10000
DB_RECORD_DELAY=6000
DB_CONN_DELAY=2000
DB_CONN_ATTEMPTS=1
PRINTER_CONN_TIMEOUT=1000
PRINTER_CONN_ATTEMPTS=2
PRINTER_CONN_PORT=9100
```
## Descripción de Archivos

View File

@ -8,8 +8,7 @@ const generateZPL = require('../resources/zplTemplate');
const label = require('../resources/label.json');
const log = require('../log')
// Función para obtener una conexión con reintentos
async function getConn(retries = 3, delay = 5000) {
async function getConn(retries = Number(env.DB_CONN_ATTEMPTS), delay = Number(env.DB_CONN_DELAY)) {
let attempt = 0;
while (attempt < retries) {
try {
@ -17,20 +16,19 @@ async function getConn(retries = 3, delay = 5000) {
} catch (error) {
attempt++;
if (attempt >= retries)
throw new Error('No se pudo obtener conexión después de múltiples intentos.');
throw new Error('Could not get connection');
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
async function sendZPL(zplContent, ipAddress, retries = 2) {
async function sendZPL(zplContent, ipAddress, retries = Number(env.PRINTER_CONN_ATTEMPTS)) {
try {
const result = await new Promise((resolve, reject) => {
const client = new net.Socket();
client.setTimeout(Number(env.PRINTER_TIMEOUT));
client.setTimeout(Number(env.PRINTER_CONN_TIMEOUT));
client.connect(Number(env.PRINTER_PORT), ipAddress, () => {
client.connect(Number(env.PRINTER_CONN_PORT), ipAddress, () => {
if (!env.DRY_PRINT)
client.write(zplContent, () => {
client.destroy();
@ -43,13 +41,13 @@ async function sendZPL(zplContent, ipAddress, retries = 2) {
});
client.on('timeout', () => {
log('error', 'Tiempo de espera agotado al conectar con la impresora');
log('error', 'Connection to the printer timed out');
client.destroy();
reject('error');
});
client.on('error', error => {
log('error', `Error al enviar ZPL a la impresora: ${error.message || error}`);
log('error', `Error sending ZPL to the printer: ${error.message || error}`);
client.destroy();
reject('error');
});
@ -57,18 +55,15 @@ async function sendZPL(zplContent, ipAddress, retries = 2) {
if (result === 'success') return true;
} catch (error) {
if (error !== 'error')
log('error', `Error inesperado al enviar ZPL a la impresora: ${error.message || error}`);
if (retries > 0) {
log('debug', `Reintentando... Quedan ${retries} intentos.`);
log('debug', `Retrying... ${retries} attempts remaining`);
return sendZPL(zplContent, ipAddress, retries - 1);
} else {
log('error', 'Todos los intentos fallaron. No se pudo enviar el ZPL.');
log('error', 'All attempts failed. Unable to send ZPL.');
return false;
}
}
}
async function getPrinterIp(printerFk, conn) {
try {
const [rows] = await conn.query(`
@ -77,14 +72,13 @@ async function getPrinterIp(printerFk, conn) {
WHERE id = ?
`, [printerFk]);
if (!rows.length)
throw new Error(`No se encontró la impresora con id = ${printerFk}`);
throw new Error(`Printer with ID ${printerFk} not found`);
return rows[0].ipAddress;
} catch (error) {
log('error', 'Error al obtener la dirección IP de la impresora:', error);
log('error', `Error retrieving the printer IP address:`, error);
throw error;
}
}
async function getRecord() {
const conn = await getConn();
try {
@ -104,17 +98,16 @@ async function getRecord() {
return record;
} catch (error) {
await conn.rollback();
log('error', 'Error al obtener y marcar el registro para procesamiento:', error);
log('error', 'Unable to retrieve and mark the record:', error);
return;
} finally {
conn.release();
}
}
async function processRecord(record) {
const conn = await getConn();
try {
log('debug', `(${record.expeditionFk}) Procesando...`);
log('debug', `(${record.expeditionFk}) Processing...`);
const zplData = generateZPL(record, label);
if (env.KEEP_TMP_FILES) {
@ -129,21 +122,20 @@ async function processRecord(record) {
if (isSendResult) {
await updateState(conn, record.expeditionFk, 11)
log('success', `(${record.expeditionFk}) Impresión realizada correctamente`);
log('success', `(${record.expeditionFk}) Print completed successfully`);
} else {
await updateState(conn, record.expeditionFk, 13)
log('error', `(${record.expeditionFk}) Error en la impresión`);
log('error', `(${record.expeditionFk}) Print not completed`);
}
parentPort.postMessage('done');
} catch (error) {
log('error', `Error al procesar el registro ${error}`);
log('error', `Unable to process the record ${error}`);
await updateState(conn, record.expeditionFk, 13)
parentPort.postMessage('error');
} finally {
conn.release();
}
}
async function updateState(conn, expeditionId, state) {
await conn.query(`
UPDATE expedition_PrintOut
@ -151,8 +143,6 @@ async function updateState(conn, expeditionId, state) {
WHERE expeditionFk = ?
`, [state, expeditionId]);
}
// Escuchar mensajes del hilo principal
parentPort.on('message', async msg => {
if (msg === 'check') {
const record = await getRecord();
@ -161,8 +151,7 @@ parentPort.on('message', async msg => {
else {
setTimeout(async() => {
parentPort.postMessage('done');
}, Number(env.GET_RECORD_DELAY));
}, Number(env.DB_RECORD_DELAY));
}
} else
processRecord(msg).catch(err => log('error', 'Error en el worker:', err));
}
});

View File

@ -9,55 +9,37 @@ class WorkerPool {
this.workers = [];
this.initWorkers(numWorkers);
}
// Inicializar workers
initWorkers(number) {
for (let i = 0; i < number; i++) this.createWorker();
}
// Crear un nuevo worker y manejar sus mensajes
createWorker() {
const worker = new Worker('./worker/worker.js');
worker.on('message', async msg => {
if (msg === 'done' || msg === 'error')
if (['done', 'error'].includes(msg))
worker.postMessage('check');
});
worker.on('error', error => {
log('error', 'Error en el worker:', error);
log('error', `Worker: ${error.message}`);
this.replaceWorker(worker);
});
worker.on('exit', code => {
if (code !== 0) {
log('error', `Worker stopped with exit code ${code}`);
setTimeout(() => {
this.replaceWorker(worker);
}, 1000);
} else {
this.workers = this.workers.filter(worker => worker !== worker);
}
});
this.workers.push(worker);
worker.postMessage('check');
}
// Reemplazar un worker fallido
replaceWorker(failedWorker) {
this.workers = this.workers.filter(worker => worker !== failedWorker);
log('debug', 'Replacing a worker...');
this.createWorker();
replaceWorker(worker) {
this.workers = this.workers.filter(w => w !== worker);
worker.terminate();
setTimeout(async() => {
log('debug', 'Replacing worker...');
this.createWorker();
}, Number(env.REPLACE_WORKER_DELAY));
}
// Asignar tareas iniciales a los workers
async start() {
const decoration = '△▽'.repeat(10);
const rfidnatura = chalk.white.bold('Rfid') + chalk.green.bold('Natura')
log(null, `${decoration} ${rfidnatura} ${decoration}`);
if (env.DRY_PRINT)
log('info', 'Dry print mode')
for (const worker of this.workers)
worker.postMessage('check'); // Pedir al worker que verifique nuevos registros
}
// Cerrar todos los workers
end() {
try {
for (const worker of this.workers) worker.terminate();