From d633fecae19e1165f2a78d37a9b42f494f02b065 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 22 Dec 2022 17:39:34 +0100 Subject: [PATCH 1/2] refs #4550 Fix: Cannot read property 'method' of undefined --- print-server.js | 55 ++++++++++++++++++++++---------------------- sql/jobData.sql | 3 ++- sql/selectQueued.sql | 3 +-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/print-server.js b/print-server.js index caab5e2..3689e44 100644 --- a/print-server.js +++ b/print-server.js @@ -73,15 +73,15 @@ class PrintServer { break; } } - async reconnect() { + async reconnect() { this.reconnectTimeout = null; - try { + try { await this.init(); - } catch (err) { - this.reconnectTimeout = setTimeout( + } catch (err) { + this.reconnectTimeout = setTimeout( () => this.reconnect(), this.conf.reconnectTimeout * 1000); - } - } + } + } async poll() { this.pollTimeout = null; try { @@ -94,12 +94,13 @@ class PrintServer { async printJob() { const conn = this.conn; const conf = this.conf; - let printJob; let jobId; + let jobData; + const args = {}; try { await conn.beginTransaction(); - [[printJob]] = await conn.query(selectQuery); + const [[printJob]] = await conn.query(selectQuery); if (!printJob) { await conn.rollback(); return; @@ -107,6 +108,16 @@ class PrintServer { jobId = printJob.id; + // Job data + const [[data]] = await conn.query(jobDataQuery, jobId); + jobData = data; + + // Job arguments + const args = {}; + const [res] = await conn.query(jobArgsQuery, jobId); + for (const row of res) + args[row.name] = row.value; + await conn.query(updateQuery, ['printing', null, jobId]); await conn.commit(); } catch (err) { @@ -115,14 +126,6 @@ class PrintServer { } try { - // Job data - // FIXME: Cannot read property 'method' of undefined - const [[jobData]] = await conn.query(jobDataQuery, jobId); - const args = {}; - const [res] = await conn.query(jobArgsQuery, jobId); - for (const row of res) - args[row.name] = row.value; - // Path params const usedParams = new Set(); const methodPath = jobData.method.replace(/{\w+}/g, function(match) { @@ -135,10 +138,7 @@ class PrintServer { let pdfData; for (let attempts = 0; !pdfData && attempts < 2; attempts++) { // URL params - const params = { - access_token: this.token, - userFk: printJob.userFk - }; + const params = {userFk: jobData.userFk}; for (const key in args) { if (!usedParams.has(key)) params[key] = args[key]; @@ -152,7 +152,8 @@ class PrintServer { url: `${conf.salix.url}/api/${methodPath}?${urlParams.toString()}`, responseType: 'arraybuffer', headers: { - 'Accept': 'application/pdf' + 'Accept': 'application/pdf', + 'Authorization': this.token } }); pdfData = response.data; @@ -203,10 +204,10 @@ class PrintServer { module.exports = PrintServer; function pExec(command) { - return new Promise(function(resolve, reject) { - exec(command, function(err, stdout, stderr) { - if (err) return reject(err); - resolve({stdout, stderr}) - }); - }); + return new Promise(function(resolve, reject) { + exec(command, function(err, stdout, stderr) { + if (err) return reject(err); + resolve({stdout, stderr}) + }); + }); } \ No newline at end of file diff --git a/sql/jobData.sql b/sql/jobData.sql index b79ff2c..f5d2e27 100644 --- a/sql/jobData.sql +++ b/sql/jobData.sql @@ -1,4 +1,5 @@ -SELECT r.name report, +SELECT pq.workerFk userFk, + r.name report, p.name printer, r.method FROM printQueue pq diff --git a/sql/selectQueued.sql b/sql/selectQueued.sql index f931a47..5f8a588 100644 --- a/sql/selectQueued.sql +++ b/sql/selectQueued.sql @@ -1,5 +1,4 @@ -SELECT pq.id, - pq.workerFk userFk +SELECT pq.id FROM printQueue pq JOIN report r ON r.id = pq.reportFk WHERE pq.statusCode = 'queued' -- 2.40.1 From 862327c2a047d202caeaf67a2a542495ba597f80 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 23 Dec 2022 14:04:24 +0100 Subject: [PATCH 2/2] refs #4550 Db connection pool, error fixes --- print-server.js | 124 ++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 66 deletions(-) diff --git a/print-server.js b/print-server.js index 3689e44..0a7874f 100644 --- a/print-server.js +++ b/print-server.js @@ -27,9 +27,7 @@ class PrintServer { await this.init(); } async init() { - this.conn = await mysql.createConnection(this.conf.db); - this.dbErrorHandler = err => this.onDbError(err); - this.conn.on('error', this.dbErrorHandler); + this.pool = await mysql.createPool(this.conf.db); console.log('Connected to DB successfully.'.green); await this.poll(); } @@ -42,14 +40,7 @@ class PrintServer { clearTimeout(this.pollTimeout); this.pollTimeout = null; } - if (this.reconnectTimeout) { - clearTimeout(this.reconnectTimeout); - this.reconnectTimeout = null; - } - this.conn.off('error', this.dbErrorHandler); - // FIXME: mysql2/promise bug, conn.end() ends process - this.conn.on('error', () => {}); - await this.conn.end(); + await this.pool.end(); } async getToken() { const salix = this.conf.salix; @@ -59,73 +50,72 @@ class PrintServer { }); this.token = response.data.token; } - async onDbError(err) { - switch(err.code) { - case 'PROTOCOL_CONNECTION_LOST': - case 'ECONNRESET': - case 1927: // ER_CONNECTION_KILLED - console.error(`DB: ${err.message}`.red); - try { - await this.end(); - } catch(e) {} - console.log('Waiting until DB is available again...'.yellow); - await this.reconnect(); - break; - } - } - async reconnect() { - this.reconnectTimeout = null; - try { - await this.init(); - } catch (err) { - this.reconnectTimeout = setTimeout( - () => this.reconnect(), this.conf.reconnectTimeout * 1000); - } - } async poll() { + let delay = this.conf.refreshRate; this.pollTimeout = null; + try { - await this.printJob(); + const conn = await this.pool.getConnection(); + + try { + if (this.dbDisconnected) { + await conn.ping(); + this.dbDisconnected = false; + console.log('DB connection recovered.'.green); + } + + if (await this.printJob(conn)) + delay = 0; + } finally { + await conn.release(); + } } catch (err) { - console.error(err) + if (err.code === 'ETIMEDOUT') { + delay = this.conf.reconnectTimeout; + if (!this.dbDisconnected) { + this.dbDisconnected = true; + console.log(`DB connection lost: ${err.message}`.red); + } + } else + console.error(err); } - this.pollTimeout = setTimeout(() => this.poll(), this.conf.refreshRate); + + this.pollTimeout = setTimeout(() => this.poll(), delay); } - async printJob() { - const conn = this.conn; + async printJob(conn) { const conf = this.conf; let jobId; - let jobData; - const args = {}; try { - await conn.beginTransaction(); - const [[printJob]] = await conn.query(selectQuery); - if (!printJob) { + let jobData; + const args = {}; + + try { + await conn.beginTransaction(); + const [[printJob]] = await conn.query(selectQuery); + if (!printJob) { + await conn.rollback(); + return; + } + + jobId = printJob.id; + + // Job data + const [[data]] = await conn.query(jobDataQuery, jobId); + jobData = data; + + // Job arguments + const [res] = await conn.query(jobArgsQuery, jobId); + for (const row of res) + args[row.name] = row.value; + + await conn.query(updateQuery, ['printing', null, jobId]); + await conn.commit(); + } catch (err) { await conn.rollback(); - return; + throw err; } - jobId = printJob.id; - - // Job data - const [[data]] = await conn.query(jobDataQuery, jobId); - jobData = data; - - // Job arguments - const args = {}; - const [res] = await conn.query(jobArgsQuery, jobId); - for (const row of res) - args[row.name] = row.value; - - await conn.query(updateQuery, ['printing', null, jobId]); - await conn.commit(); - } catch (err) { - await conn.rollback(); - throw err; - } - - try { // Path params const usedParams = new Set(); const methodPath = jobData.method.replace(/{\w+}/g, function(match) { @@ -176,7 +166,7 @@ class PrintServer { // Print PDF try { - await pExec(`lp -d "${printer}" "${tmpFilePath}"`); + //await pExec(`lp -d "${printer}" "${tmpFilePath}"`); } catch(err) { await fs.unlink(tmpFilePath); throw new Error(`Print error: ${err.message}`); @@ -198,6 +188,8 @@ class PrintServer { await conn.query(updateQuery, ['error', message, jobId]); throw new Error(`(${jobId}) ${message}`); } + + return jobId; } } -- 2.40.1