/** * Test case for figuring out robust way to recognize if connection is dead * for mysql based drivers. */ const Bluebird = require('bluebird'); const toxiproxy = require('toxiproxy-node-client'); const toxicli = new toxiproxy.Toxiproxy('http://localhost:8474'); const rp = require('request-promise-native'); async function stdMysqlQuery(con, sql) { return new Promise((resolve, reject) => { try { con.query({ sql, timeout: 4000 }, function (error, results, fields) { if (error) { reject(error); } else { resolve(results); } }); } catch (err) { reject(err); // double sure... } }); } // ALL THE DRIVERS HAS DIFFERENT BAG OF TRICKS TO RECOVER AND // RECOGNIZE WHEN CONNECTION HAS BEEN CLOSED // ------------- setup mysql db driver connection const mysql = require('mysql'); let mysqlCon = {state: 'disconnected'}; async function mysqlQuery(sql) { // best way to check if connection is still alive if (mysqlCon.state === 'disconnected') { console.log('reconnecting mysql'); mysqlCon = mysql.createConnection({ host: 'localhost', user: 'root', password: 'mysqlrootpassword', port: 23306, connectTimeout: 500 }); // not always triggered, if this happens during query mysqlCon.on('error', err => { console.log('- STATS Mysql connection died:', err); }); } return stdMysqlQuery(mysqlCon, sql); } // ------------- setup mysql2 db driver connection const mysql2 = require('mysql2'); let mysql2Con = {_fatalError: 'initmefirst'}; async function mysql2Query(sql) { if (mysql2Con._fatalError) { console.log('reconnecting mysql2'); mysql2Con = mysql2.createConnection({ host: 'localhost', user: 'root', password: 'mysqlrootpassword', port: 23306, connectTimeout: 500 }); mysql2Con.on('error', err => { console.log('- STATS Mysql2 connection died:', err); }); } console.log('================ MYSQL2 Running query....'); const res = await stdMysqlQuery(mysql2Con, sql); console.log('=========== done'); return res; } const counters = {}; function setMysqlQueryCounters(name) { const counts = counters[name] = {queries: 0, results: 0, errors: 0}; } setMysqlQueryCounters('mysql'); setMysqlQueryCounters('mysql2'); const _ = require('lodash'); // start printing out counters let lastCounters = _.cloneDeep(counters); setInterval(() => { const reqsPerSec = {}; for (let key of Object.keys(counters)) { reqsPerSec[key] = { queries: (counters[key].queries - lastCounters[key].queries), results: (counters[key].results - lastCounters[key].results), errors: (counters[key].errors - lastCounters[key].errors), } } console.log('------------------------ STATS PER SECOND ------------------------'); console.dir(reqsPerSec, {colors: true}); console.log('------------------------------- EOS ------------------------------'); lastCounters = _.cloneDeep(counters); // if hang ///if (reqsPerSec.mysql2.queries === 0) process.exit(0); }, 1000); async function main() { async function recreateProxy(serviceName, listenPort, proxyToPort) { try { await rp.delete({ url: `${toxicli.host}/proxies/${serviceName}` }); } catch(err) {} const proxy = await toxicli.createProxy({ name: serviceName, listen: `0.0.0.0:${listenPort}`, upstream: `${serviceName}:${proxyToPort}` }); // add some latency await proxy.addToxic(new toxiproxy.Toxic(proxy, { type: 'latency', attributes: {latency: 1, jitter: 1} })); // cause connections to be closed every some transferred bytes await proxy.addToxic(new toxiproxy.Toxic(proxy, { type: 'limit_data', attributes: {bytes: 1000} })); } // create TCP proxies for simulating bad connections etc. async function recreateProxies() { console.log('----- Recreating proxies -> cutting connections completely'); await recreateProxy('postgresql', 25432, 5432); await recreateProxy('mysql', 23306, 3306); await recreateProxy('oracledbxe', 21521, 1521); } setInterval(() => recreateProxies(), 2000); async function loopQueries(prefix, query) { const counts = counters[prefix]; while(true) { try { counts.queries += 1; // without this delay we endup to busy failure loop await Bluebird.delay(0); await query(); counts.results += 1; } catch (err) { counts.errors += 1; console.log(prefix, err); } } } await recreateProxies(); loopQueries('mysql', () => mysqlQuery('select 1')); loopQueries('mysql2', () => mysql2Query('select 1')); // wait forever while(true) { await Bluebird.delay(1000); } } main().then(() => console.log('DONE')).catch(err => console.log(err));