123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /**
- * 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));
|