Add initial version of dijkstra backend cloudron image

This commit is contained in:
2020-10-12 11:27:15 +02:00
commit 4f5db9ab26
4209 changed files with 448228 additions and 0 deletions

126
node_modules/knex/scripts/build.js generated vendored Normal file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const child_process = require('child_process');
const Promise = require('bluebird');
const _ = require('lodash');
const exec = function(cmd, args) {
return new Promise(function(resolve, reject) {
// Execute command
const child = child_process.exec(cmd, {
cwd: process.cwd(),
env: process.env,
});
// Pass stdout and stderr
child.stdout.on('data', function(data) {
process.stdout.write(data.toString());
});
child.stderr.on('data', function(data) {
process.stderr.write(data.toString());
});
// Handle result
child.on('exit', function(code) {
if (code) reject(code);
else resolve();
});
child.on('error', reject);
});
};
const CWD = process.cwd();
const POSTINSTALL_BUILD_CWD = process.env.POSTINSTALL_BUILD_CWD;
// If we didn't have this check, then we'd be stuck in an infinite `postinstall`
// loop, since we run `npm install --only=dev` below, triggering another
// `postinstall`. We can't use `--ignore-scripts` because that ignores scripts
// on all the modules that get installed, too, which would break stuff. So
// instead, we set an environment variable, `POSTINSTALL_BUILD_CWD`, that keeps
// track of what we're installing. It's more than just a yes/no flag because
// the dev dependencies we're installing might use `postinstall-build` too, and
// we don't want the flag to prevent them from running.
if (POSTINSTALL_BUILD_CWD !== CWD) {
const BUILD_ARTIFACT = process.argv[2];
const BUILD_COMMAND = process.argv[3];
fs.stat(BUILD_ARTIFACT, function(err, stats) {
if (err || !(stats.isFile() || stats.isDirectory())) {
// This script will run again after we run `npm install` below. Set an
// environment variable to tell it to skip the check. Really we just want
// the execSync's `env` to be modified, but it's easier just modify and
// pass along the entire `process.env`.
process.env.POSTINSTALL_BUILD_CWD = CWD;
// We already have prod dependencies, that's what triggered `postinstall`
// in the first place. So only install dev.
// Fetch package.json
const pkgJson = require(path.join(CWD, 'package.json'));
const devDeps = pkgJson.devDependencies;
// Values listed under `buildDependencies` contain the dependency names
// that are required for `lib` building.
const buildDependencies = _.pick(devDeps, pkgJson.buildDependencies);
// Proceed only if there is something to install
if (!_.isEmpty(buildDependencies)) {
const opts = { env: process.env, stdio: 'inherit' };
console.log('Building Knex.js');
// Map all key (dependency) value (semver) pairs to
// "dependency@semver dependency@semver ..." string that can be used
// for `npm install` command
const installArgs = _(buildDependencies)
.pickBy(function(semver, dep) {
// Check if the dependency is already installed
try {
require(dep);
return false;
} catch (err) {
return true;
}
})
.map(function(semver, dep) {
// Format installable dependencies
return dep + '@' + semver;
})
.value()
.join(' ');
const needsDepInstallation = !_.isEmpty(installArgs);
const dependenciesInstalledQ = needsDepInstallation
? exec('npm install ' + installArgs, opts)
: Promise.resolve();
dependenciesInstalledQ
.then(function(stdout, stderr) {
console.log('✓');
// Don't need the flag anymore as `postinstall` was already run.
// Change it back so the environment is minimally changed for the
// remaining commands.
process.env.POSTINSTALL_BUILD_CWD = POSTINSTALL_BUILD_CWD;
console.log('Building compiled files (' + BUILD_COMMAND + ')');
return exec(BUILD_COMMAND, opts);
})
.catch(function(err) {
console.error(err);
process.exit(1);
})
.then(function(stdout, stderr) {
if (process.env.NODE_ENV === 'production') {
console.log('✓');
console.log('Pruning dev dependencies for production build');
return exec('npm prune --production', opts);
} else {
console.log('Skipping npm prune');
}
})
.then(function() {
console.log('✓');
})
.catch(function(err) {
console.error(err);
process.exit(1);
});
}
}
});
}

97
node_modules/knex/scripts/docker-compose.yml generated vendored Normal file
View File

@@ -0,0 +1,97 @@
version: '3'
services:
mssql:
image: microsoft/mssql-server-linux:2017-latest
ports:
- '21433:1433'
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=S0meVeryHardPassword
healthcheck:
test: /opt/mssql-tools/bin/sqlcmd -S mssql -U sa -P 'S0meVeryHardPassword' -Q 'select 1'
initmssqlknexdb:
image: microsoft/mssql-server-linux:2017-latest
links:
- mssql
depends_on:
- mssql
entrypoint:
- bash
- -c
- 'until /opt/mssql-tools/bin/sqlcmd -S mssql -U sa -P S0meVeryHardPassword -d master -Q "CREATE DATABASE knex_test"; do sleep 5; done'
mysql:
image: mysql
command: --default-authentication-plugin=mysql_native_password
ports:
- '23306:3306'
environment:
- MYSQL_ROOT_PASSWORD=testrootpassword
- MYSQL_DATABASE=knex_test
- MYSQL_USER=testuser
- MYSQL_PASSWORD=testpassword
healthcheck:
test:
[
'CMD',
'/usr/bin/mysql',
'-hlocalhost',
'-utestuser',
'-ptestpassword',
'-e',
'SELECT 1',
]
interval: 30s
timeout: 5s
retries: 3
restart: always
waitmysql:
image: mysql
links:
- mysql
depends_on:
- mysql
entrypoint:
- bash
- -c
- 'until /usr/bin/mysql -hmysql -utestuser -ptestpassword -e "SELECT 1"; do sleep 5; done'
postgres:
image: postgres:alpine
ports:
- '25432:5432'
environment:
- POSTGRES_USER=testuser
- POSTGRES_PASSWORD=knextest
- POSTGRES_DB=knex_test
waitpostgres:
image: postgres:alpine
links:
- postgres
depends_on:
- postgres
entrypoint:
- bash
- -c
- 'until /usr/local/bin/psql postgres://testuser:knextest@postgres/knex_test -c "SELECT 1"; do sleep 5; done'
oracledbxe:
image: quillbuilduser/oracle-18-xe
container_name: oracledbxe_container
ports:
- '21521:1521'
environment:
- ORACLE_ALLOW_REMOTE=true
waitoracledbxe:
image: quillbuilduser/oracle-18-xe
links:
- oracledbxe
depends_on:
- oracledbxe
environment:
- ORACLE_HOME=/opt/oracle/product/18c/dbhomeXE
entrypoint:
- bash
- -c
- 'until /opt/oracle/product/18c/dbhomeXE/bin/sqlplus -s sys/Oracle18@oracledbxe/XE as sysdba <<< "SELECT 13376411 FROM DUAL; exit;" | grep "13376411"; do echo "Could not connect to oracle... sleep for a while"; sleep 5; done'

24
node_modules/knex/scripts/next-release-howto.md generated vendored Normal file
View File

@@ -0,0 +1,24 @@
# Checklist for crating knex @next releases
1. Go through all commits since the last release and add them to CHANGELOG.md under unreleased changes section.
2. Commit changes to CHANGELOG
3. Check that master compiles and tests are running fine (check also that CI tests are passing)
```
npm run build
# run bunch of tests, but skipping coverage which doesn't really work locally at least
npm plaintest
npm bin_test
npm oracledb:test
npm mssql:init
npm mssql:test
npm mssql:destroy
```
4. Update package.json version to be e.g. 0.16.0-next1 or 0.16.0-next2 and commit yo master
5. Publish it under @next tag
```
npm publish --tag next
```

34
node_modules/knex/scripts/release.sh generated vendored Normal file
View File

@@ -0,0 +1,34 @@
#!/bin/bash -e
changelog=node_modules/.bin/changelog
update_version() {
echo "$(node -p "p=require('./${1}');p.version='${2}';JSON.stringify(p,null,2)")" > $1
echo "Updated ${1} version to ${2}"
}
current_version=$(node -p "require('./package').version")
printf "Next version (current is $current_version)? "
read next_version
if ! [[ $next_version =~ ^[0-9]\.[0-9]+\.[0-9](-.+)? ]]; then
echo "Version must be a valid semver string, e.g. 1.0.2 or 2.3.0-beta.1"
exit 1
fi
next_ref="v$next_version"
git add -u
npm run build
npm test
update_version 'package.json' $next_version
git commit -am "release $next_version"
git tag $next_version
git push --tags
npm publish

34
node_modules/knex/scripts/runkit-example.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
require('sqlite3');
const Knex = require('knex');
const knexSqlite = Knex({
client: 'sqlite',
connection: ':memory:',
});
const knexMysql = Knex({
client: 'mysql2',
});
const knexPg = Knex({
client: 'pg',
});
(async function run() {
await knexSqlite.schema.createTable('test', (t) => {
t.increments('id').primary();
t.string('data');
});
await knexSqlite('test').insert([{ data: 'foo' }, { data: 'bar' }]);
console.log('test table data:', await knexSqlite('test'));
console.log(
knexPg({ f: 'foo', b: 'bar' })
.select('foo.*')
.where('f.name', knexPg.raw('??', ['b.name']))
.whereIn('something', knexPg('bar').select('id'))
.toSQL().sql
);
})();

18
node_modules/knex/scripts/stress-test/README.txt generated vendored Normal file
View File

@@ -0,0 +1,18 @@
# Test scripts to evaluate stability of drivers / pool etc.
# To run this test you need to be in this directory + have node >= 8
# and startup docker containers with proxy and sql servers
docker-compose up --no-start
docker-compose start
# Select different test script to run:
node mysql2-random-hanging-every-now-and-then.js 2> /dev/null | grep -B500 -A2 -- "- STATS"
node mysql2-sudden-exit-without-error
node knex-stress-test.js | grep -A 3 -- "- STATS "
node reconnect-test-mysql-based-drivers.js 2> /dev/null | grep -A 3 -- "- STATS "
# Shut down docker instances when done:
docker-compose down

View File

@@ -0,0 +1,47 @@
version: '3'
services:
toxiproxy:
image: shopify/toxiproxy
ports:
- "8474:8474"
- "23306:23306"
- "25432:25432"
- "21521:21521"
- "21433:21433"
links:
- "mysql"
- "postgresql"
- "oracledbxe"
- "mssql"
mysql:
image: mysql:5.7
ports:
- "33306:3306"
environment:
- TZ=UTC
- MYSQL_ROOT_PASSWORD=mysqlrootpassword
postgresql:
image: mdillon/postgis
ports:
- "35432:5432"
environment:
- POSTGRES_PASSWORD=postgresrootpassword
- POSTGRES_USER=postgres
oracledbxe:
image: wnameless/oracle-xe-11g
ports:
- "31521:1521"
environment:
- ORACLE_ALLOW_REMOTE=true
mssql:
image: microsoft/mssql-server-linux:2017-latest
ports:
- "31433:1433"
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=S0meVeryHardPassword

View File

@@ -0,0 +1,196 @@
const Knex = require('../../lib');
const Bluebird = require('bluebird');
const toxiproxy = require('toxiproxy-node-client');
const toxicli = new toxiproxy.Toxiproxy('http://localhost:8474');
const rp = require('request-promise-native');
// init instances
const pg = Knex({
client: 'pg',
connection:
'postgres://postgres:postgresrootpassword@localhost:25432/postgres',
pool: { max: 50 },
});
const mysql2 = Knex({
client: 'mysql2',
connection:
'mysql://root:mysqlrootpassword@localhost:23306/?charset=utf8&connectTimeout=500',
pool: { max: 50 },
});
const mysql = Knex({
client: 'mysql',
connection:
'mysql://root:mysqlrootpassword@localhost:23306/?charset=utf8&connectTimeout=500',
pool: { max: 50 },
});
const mssql = Knex({
client: 'mssql',
connection: {
port: 21433,
user: 'sa',
password: 'S0meVeryHardPassword',
server: 'localhost',
requestTimeout: 500,
},
pool: { max: 50 },
});
/* TODO: figure out how to nicely install oracledb node driver on osx
const oracledb = Knex({
client: 'oracledb',
connection: {
user : "travis",
password : "travis",
connectString : "localhost/XE",
// https://github.com/oracle/node-oracledb/issues/525
stmtCacheSize : 0
},
pool: { max: 50 }
});
*/
const counters = {};
function setQueryCounters(instance, name) {
const counts = (counters[name] = { queries: 0, results: 0, errors: 0 });
instance.on('query', () => (counts.queries += 1));
instance.on('query-response', () => (counts.results += 1));
instance.on('query-error', () => (counts.errors += 1));
}
setQueryCounters(pg, 'pg');
setQueryCounters(mysql, 'mysql');
setQueryCounters(mysql2, 'mysql2');
setQueryCounters(mssql, 'mssql');
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) / 2,
results: (counters[key].results - lastCounters[key].results) / 2,
errors: (counters[key].errors - lastCounters[key].errors) / 2,
};
}
console.log(
'------------------------ STATS PER SECOND ------------------------'
);
console.dir(reqsPerSec, { colors: true });
console.log(
'------------------------------- EOS ------------------------------'
);
lastCounters = _.cloneDeep(counters);
}, 2000);
async function killConnectionsPg() {
return pg.raw(`SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'postgres'
AND pid <> pg_backend_pid()`);
}
async function killConnectionsMyslq(client) {
const [rows, colDefs] = await client.raw(`SHOW FULL PROCESSLIST`);
await Promise.all(rows.map((row) => client.raw(`KILL ${row.Id}`)));
}
async function killConnectionsMssql() {
const rows = await mssql('sys.dm_exec_sessions').select('session_id');
await Promise.all(rows.map((row) => mssql.raw(`KILL ${row.session_id}`)));
}
async function main() {
async function loopQueries(prefix, query) {
const queries = () => [...Array(50).fill(query)];
while (true) {
try {
await Promise.all(queries());
} catch (err) {
console.log(prefix, err);
}
}
}
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 500 bytes
await proxy.addToxic(
new toxiproxy.Toxic(proxy, {
type: 'limit_data',
attributes: { bytes: 5000 },
})
);
}
// create TCP proxies for simulating bad connections etc.
async function recreateProxies() {
await recreateProxy('postgresql', 25432, 5432);
await recreateProxy('mysql', 23306, 3306);
await recreateProxy('oracledbxe', 21521, 1521);
await recreateProxy('mssql', 21433, 1433);
}
await recreateProxies();
loopQueries('PSQL:', pg.raw('select 1'));
loopQueries('PSQL TO:', pg.raw('select 1').timeout(20));
loopQueries('MYSQL:', mysql.raw('select 1'));
loopQueries('MYSQL TO:', mysql.raw('select 1').timeout(20));
// mysql2 still crashes app (without connection killer nor timeouts)
// https://github.com/sidorares/node-mysql2/issues/731
// loopQueries('MYSQL2:', mysql2.raw('select 1'));
// loopQueries('MYSQL2 TO:', mysql2.raw('select 1').timeout(20));
loopQueries('MSSQL:', mssql.raw('select 1'));
loopQueries('MSSQL TO:', mssql.raw('select 1').timeout(20));
setInterval(recreateProxies, 2000);
while (true) {
await Bluebird.delay(20); // kill everything every quite often from server side
try {
await Promise.all([
killConnectionsPg(),
killConnectionsMyslq(mysql),
// killConnectionsMyslq(mysql2),
killConnectionsMssql(),
]);
} catch (err) {
console.log('KILLER ERROR:', err);
}
}
}
process.on('exit', () => console.log('- STATS PRINT NEAR END LOGS ')); // marker for grep...
main();

View File

@@ -0,0 +1,145 @@
/**
* 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');
const _ = require('lodash');
async function stdMysqlQuery(con, sql) {
return new Promise((resolve, reject) => {
try {
con.query(
{
sql,
timeout: 500,
},
function(error, results, fields) {
if (error) {
reject(error);
} else {
resolve(results);
}
}
);
} catch (err) {
reject(err); // double sure...
}
});
}
const mysql2 = require('mysql2');
let mysql2Con = { _fatalError: 'initmefirst' };
async function mysql2Query(sql) {
// recreate connection on fatal error
if (mysql2Con._fatalError) {
console.log('========== Reconnecting mysql2');
mysql2Con = mysql2.createConnection({
host: 'localhost',
user: 'root',
password: 'mysqlrootpassword',
port: 23306,
connectTimeout: 500,
debug: true,
});
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('mysql2');
// 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);
}, 1000);
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 },
})
);
}
async function main() {
await recreateProxy('mysql', 23306, 3306);
setInterval(() => recreateProxy('mysql', 23306, 3306), 2000);
async function loopQueries(prefix, query) {
const counts = counters[prefix];
while (true) {
try {
counts.queries += 1;
// without this delay we might endup to busy failure loop
await Bluebird.delay(0);
await query();
counts.results += 1;
} catch (err) {
counts.errors += 1;
console.log(prefix, err);
}
}
}
loopQueries('mysql2', () => mysql2Query('select 1'));
// wait forever
while (true) {
await Bluebird.delay(1000);
}
}
main()
.then(() => console.log('DONE'))
.catch((err) => console.log(err));

View File

@@ -0,0 +1,100 @@
/**
* Test case when mysql2 driver strangely exits when one tries to send query
* to dead connection.
*/
const Bluebird = require('bluebird');
const toxiproxy = require('toxiproxy-node-client');
const toxicli = new toxiproxy.Toxiproxy('http://localhost:8474');
const rp = require('request-promise-native');
// drops old toxicproxy and creates new
async function recreateProxy(serviceName, listenPort, proxyToPort) {
try {
await rp.delete({
url: `${toxicli.host}/proxies/${serviceName}`,
});
} catch (err) {
// there was no proxy by that name... its ok
}
const proxy = await toxicli.createProxy({
name: serviceName,
listen: `0.0.0.0:${listenPort}`,
upstream: `${serviceName}:${proxyToPort}`,
});
}
async function insanelyParanoidQuery(con) {
console.log('sending query');
const res = await new Promise((resolve, reject) => {
try {
con.query('select 1', [], function(err, rows, fields) {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
} catch (err) {
console.log('Huh synchronous exception?! (shouldnt be possible)');
reject(err);
}
});
console.log(res);
}
async function main() {
// create proxy from localhost:23306 -> mysqldocker:3306
await recreateProxy('mysql', 23306, 3306);
// ------------- setup mysql2 db driver connection
const mysql2 = require('mysql2'); // with mysql this works...
const mysql2Con = await mysql2.createConnection({
host: 'localhost',
user: 'root',
password: 'mysqlrootpassword',
port: 23306,
});
mysql2Con.on('error', function(err) {
console.log("I'm dead", err);
});
console.log('Going to cut connections');
// cut connection during recreate
await recreateProxy('mysql', 23306, 3306);
console.log('Proxy recreated... start waiting');
// wait forever
while (true) {
await Bluebird.delay(1000);
try {
await insanelyParanoidQuery(mysql2Con);
} catch (err) {
console.log('query failed:', err);
}
await recreateProxy('mysql', 23306, 3306);
}
}
main()
.then(() => console.log('Process stopped normally'))
.catch((err) => {
console.log('Process stopped to failure', err);
});
console.log('Waiting for eventloop to stop...');
process.on('uncaughtException', function(err) {
console.log('uncaughtException', err);
});
process.on('exit', function() {
console.log(
'Did someone call process.exit() or wat? exitCode:',
process.exitCode
);
});

View File

@@ -0,0 +1,184 @@
/**
* 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));