mysql2-random-hanging-every-now-and-then.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * Test case for figuring out robust way to recognize if connection is dead
  3. * for mysql based drivers.
  4. */
  5. const Bluebird = require('bluebird');
  6. const toxiproxy = require('toxiproxy-node-client');
  7. const toxicli = new toxiproxy.Toxiproxy('http://localhost:8474');
  8. const rp = require('request-promise-native');
  9. const _ = require('lodash');
  10. async function stdMysqlQuery(con, sql) {
  11. return new Promise((resolve, reject) => {
  12. try {
  13. con.query({
  14. sql,
  15. timeout: 500
  16. }, function (error, results, fields) {
  17. if (error) {
  18. reject(error);
  19. } else {
  20. resolve(results);
  21. }
  22. });
  23. } catch (err) {
  24. reject(err); // double sure...
  25. }
  26. });
  27. }
  28. const mysql2 = require('mysql2');
  29. let mysql2Con = {_fatalError: 'initmefirst'};
  30. async function mysql2Query(sql) {
  31. // recreate connection on fatal error
  32. if (mysql2Con._fatalError) {
  33. console.log('========== Reconnecting mysql2');
  34. mysql2Con = mysql2.createConnection({
  35. host: 'localhost',
  36. user: 'root',
  37. password: 'mysqlrootpassword',
  38. port: 23306,
  39. connectTimeout: 500,
  40. debug: true
  41. });
  42. mysql2Con.on('error', err => {
  43. console.log('- STATS Mysql2 connection died:', err);
  44. });
  45. }
  46. console.log('================ MYSQL2 Running query ======');
  47. const res = await stdMysqlQuery(mysql2Con, sql);
  48. console.log('====================== done ================');
  49. return res;
  50. }
  51. const counters = {};
  52. function setMysqlQueryCounters(name) {
  53. const counts = counters[name] = {queries: 0, results: 0, errors: 0};
  54. }
  55. setMysqlQueryCounters('mysql2');
  56. // start printing out counters
  57. let lastCounters = _.cloneDeep(counters);
  58. setInterval(() => {
  59. const reqsPerSec = {};
  60. for (let key of Object.keys(counters)) {
  61. reqsPerSec[key] = {
  62. queries: (counters[key].queries - lastCounters[key].queries),
  63. results: (counters[key].results - lastCounters[key].results),
  64. errors: (counters[key].errors - lastCounters[key].errors),
  65. }
  66. }
  67. console.log('------------------------ STATS PER SECOND ------------------------');
  68. console.dir(reqsPerSec, {colors: true});
  69. console.log('------------------------------- EOS ------------------------------');
  70. lastCounters = _.cloneDeep(counters);
  71. }, 1000);
  72. async function recreateProxy(serviceName, listenPort, proxyToPort) {
  73. try {
  74. await rp.delete({
  75. url: `${toxicli.host}/proxies/${serviceName}`
  76. });
  77. } catch(err) {}
  78. const proxy = await toxicli.createProxy({
  79. name: serviceName,
  80. listen: `0.0.0.0:${listenPort}`,
  81. upstream: `${serviceName}:${proxyToPort}`
  82. });
  83. // add some latency
  84. await proxy.addToxic(new toxiproxy.Toxic(proxy, {
  85. type: 'latency',
  86. attributes: {latency: 1, jitter: 1}
  87. }));
  88. // cause connections to be closed every some transferred bytes
  89. await proxy.addToxic(new toxiproxy.Toxic(proxy, {
  90. type: 'limit_data',
  91. attributes: {bytes: 1000}
  92. }));
  93. }
  94. async function main() {
  95. await recreateProxy('mysql', 23306, 3306);
  96. setInterval(() => recreateProxy('mysql', 23306, 3306), 2000);
  97. async function loopQueries(prefix, query) {
  98. const counts = counters[prefix];
  99. while(true) {
  100. try {
  101. counts.queries += 1;
  102. // without this delay we might endup to busy failure loop
  103. await Bluebird.delay(0);
  104. await query();
  105. counts.results += 1;
  106. } catch (err) {
  107. counts.errors += 1;
  108. console.log(prefix, err);
  109. }
  110. }
  111. }
  112. loopQueries('mysql2', () => mysql2Query('select 1'));
  113. // wait forever
  114. while(true) {
  115. await Bluebird.delay(1000);
  116. }
  117. }
  118. main().then(() => console.log('DONE')).catch(err => console.log(err));