diff --git a/lib/db-mysql.js b/lib/db-mysql.js index a06ce1d..da5f0a8 100644 --- a/lib/db-mysql.js +++ b/lib/db-mysql.js @@ -1,36 +1,125 @@ -'use strict'; +const HEALTHY_CHECK_INTERVAL_MS = 10000; + +const MODULE_NAME = require('path').basename(__filename); const mysql = require('mysql'); const config = require('komodo-sdk/config'); +const logger = require('komodo-sdk/logger'); + +const connectionLimit = config.mysql && config.mysql.pool_connection_limit + ? config.mysql.pool_connection_limit + : 0; -const connectionLimit = config.mysql && config.mysql.pool_connection_limit ? config.mysql.pool_connection_limit : 0; +const ERROR_POOL_NOT_READY = new Error(`${MODULE_NAME}: pool is not ready`); +exports.ERROR_POOL_NOT_READY = ERROR_POOL_NOT_READY; const pool = config.mysql ? mysql.createPool({ - connectionLimit: connectionLimit, + connectionLimit, host: config.mysql.host || 'localhost', database: config.mysql.database || 'komodo', user: config.mysql.user || 'komodo', - password: config.mysql.password + password: config.mysql.password, + timezone: config.mysql.timezone, }) : null; exports.pool = pool; -exports.format = (sql, values) => { - return new Promise((resolve, reject) => { - if (!pool) { - reject('Missing DB config'); +exports.query = (query, values, cb) => { + // pool.query.apply(null, arguments); + if (!pool || !pool.query) { + logger.warn(`${MODULE_NAME}: ${ERROR_POOL_NOT_READY.toString()}`); + if (typeof cb === 'function') { + cb(ERROR_POOL_NOT_READY); + } + + return; + } + + pool.query(query, values, cb); +}; + +exports.format = (sql, values, cb) => new Promise((resolve, reject) => { + if (!pool) { + reject(ERROR_POOL_NOT_READY); + if (typeof cb === 'function') cb(ERROR_POOL_NOT_READY); + return; + } + + pool.getConnection((err, connection) => { + if (err) { + reject(err); + if (typeof cb === 'function') cb(err); + return; + } + + const formatted = connection.format(sql, values); + connection.release(); + + resolve(formatted); + if (typeof cb === 'function') cb(null, formatted); + }); +}); + +exports.beginConnection = (cb) => new Promise((resolve) => { + pool.getConnection((errGetConnection, connection) => { + if (errGetConnection) { + resolve([errGetConnection]); + if (typeof cb === 'function') cb(errGetConnection); return; } - pool.getConnection((err, connection) => { - if (err) { - reject(err); + connection.beginTransaction((errBeginTransaction) => { + if (errBeginTransaction) { + resolve([errBeginTransaction]); + if (typeof cb === 'function') cb(errBeginTransaction); return; } - resolve(connection.format(sql, values)); - connection.release(); + resolve([null, connection]); + if (typeof cb === 'function') cb(null, connection); }); - }) -} \ No newline at end of file + }); +}); + +exports.getBy = (tableName, fieldName, value, cb) => new Promise((resolve) => { + const query = 'SELECT * FROM ?? WHERE ?? = ? LIMIT 1'; + const values = [tableName, fieldName, value]; + pool.query(query, values, (err, results) => { + const result = results && results[0]; + resolve([err, result || null]); + if (typeof cb === 'function') cb(err, result || null); + }); +}); + +function healthyCheck() { + const query = 'SELECT 1'; + const values = []; + + if (!pool) { + logger.warn(`${MODULE_NAME}: Skip healthy check on undefined pool (ERR-EB9E5C08)`); + return; + } + + if (!pool.query) { + logger.warn(`${MODULE_NAME}: Skip healthy check on undefined pool.query (ERR-D10F70F3)`); + return; + } + + pool.query(query, values, (err) => { + if (err) { + logger.warn(`${MODULE_NAME}: Error on healthy check (ERR-38EC9B78)`, { err }); + } + }); +} + +setInterval(() => { + const randomMs = Math.floor(Math.random() * HEALTHY_CHECK_INTERVAL_MS * 0.3); + setTimeout(() => { + try { + healthyCheck(); + } catch (err) { + logger.warn(`${MODULE_NAME}: Exception on periodic healthy check (ERR-2D137502)`, { err }); + } + }, randomMs); +}, HEALTHY_CHECK_INTERVAL_MS); diff --git a/lib/messages-archive.js b/lib/messages-archive.js index 6773785..a37abfa 100644 --- a/lib/messages-archive.js +++ b/lib/messages-archive.js @@ -52,7 +52,10 @@ function insert(params, direction) { direction ); - if (!db.pool) return; + if (!db.pool) { + logger.warn('MESSAGE-ARCHIVE: DB POOL is not ready to insert message history'); + return; + } const query = `INSERT INTO messages SET ?`; const values = [{ @@ -63,9 +66,10 @@ function insert(params, direction) { message: (params.msg || params.message).trim(), }]; - db.pool.query(query, values, (err) => { + db.pool.query(query, values, async (err) => { if (err) { - logger.warn(`MESSAGES-ARCHIVE: DB ERROR on inserting message. ${err.toString()}`); + const fullQuery = await db.format(query, values); + logger.warn(`MESSAGES-ARCHIVE: DB ERROR on inserting message. ${err.toString()}`, { query: fullQuery }); } }); }