UNPKG

hystrixjs

Version:

resilience module for NodeJS applications

205 lines (182 loc) 6.64 kB
var cluster = require('cluster'), minimist = require('minimist'), Stats = require('./stats'), Service = require('./service'), EndUser = require('./end_user'), App = require('./app'); var opts = { USER_WORKERS: 2, USERS_PER_WORKER: 5, USERS_MIN_SLEEP: 100, USERS_MAX_SLEEP: 750, SERVICE_PORT_1: 3001, SERVICE_PORT_2: 3002, SERVICE_PORT_3: 3003, APP_PORT_1: 3013, APP_PORT_2: 3004, STATS_S2S_PORT: 3005, STATS_WEBUI_PORT: 3000, GLOBALAGENT_MAXSOCKETS: 1000 }; function help() { console.log("usage: %s [options]", process.argv.slice(0, 2).join(" ")); console.log("\n\nThis example will spawn several node processes simulating two app servers, three backend services, one stats server, and a configurable amount of 'user workers' simulating end-user requests.\n\nThe app servers make requests to the three backend services through circuit breakers and push their metrics to the stats server, which has a monitoring web-UI.\n\n"); console.log("-h, --help Print this help and exit"); console.log("--user-workers Number of childs to fork which simulate end-user requests (default: %d)", opts.USER_WORKERS); console.log("--users-per-worker Number or users to simulate per worker child (default: %d)", opts.USERS_PER_WORKER); console.log("--users-min-sleep Minimum milliseconds to sleep before performing another request (default: %d)", opts.USERS_MIN_SLEEP); console.log("--users-max-sleep Maximum milliseconds to sleep before performing another request (default: %d)", opts.USERS_MAX_SLEEP); console.log("--service-port-{1,2,3} Port to listen on for the service number N (1,2,3) (defaults: %d, %d, %d)", opts.SERVICE_PORT_1, opts.SERVICE_PORT_2, opts.SERVICE_PORT_3); console.log("--app-port-{1,2} Port to listen on for the app N (1,2) (defaults: %d, %d)", opts.APP_PORT_1, opts.APP_PORT_2); console.log("--stats-s2s-port Port to listen for stats collection (default: %d)", opts.STATS_S2S_PORT); console.log("--stats-webui-port Port where the stats server servers the web UI (default: %d)", opts.STATS_WEBUI_PORT); console.log("--globalagent-maxsockets http.globalAgent.maxSockets value (default: %d)", opts.GLOBALAGENT_MAXSOCKETS); } var argv = minimist(process.argv.slice(2)); if (argv.h || argv.help) { help(); process.exit(); } for (var capsK in opts) { var k = capsK.toLowerCase().replace(/_/g, '-'); if (!(k in argv)) { continue; } var num = parseInt(argv[k]); if (isNaN(num)) { console.log("Option --%s should be a number! (%s given)", k, argv[k]); process.exit(1); } opts[capsK] = num; } require('http').globalAgent.maxSockets = opts.GLOBALAGENT_MAXSOCKETS; var services = [{ port: opts.SERVICE_PORT_1, timeout: 700, resetTime: 1000, concurrency: 6, errorThreshold: 10, errorNamesThresholds: { ServiceUnavailableError: 0 }, // app will make N calls to this service per user request calls: 3, // app will tell service to random sleep until N ms sleep: 300 }, { port: opts.SERVICE_PORT_2, timeout: 1000, resetTime: 600, concurrency: 6, errorThreshold: 10, errorNamesThresholds: { ServiceUnavailableError: 0 }, calls: 6, sleep: 1200 }, { port: opts.SERVICE_PORT_3, timeout: 1300, resetTime: 600, concurrency: 4, errorThreshold: 10, errorNamesThresholds: { ServiceUnavailableError: 0 }, calls: 2, sleep: 100 }]; var apps = [opts.APP_PORT_1, opts.APP_PORT_2]; var statsServer = { webPort: opts.STATS_WEBUI_PORT, ioPort: opts.STATS_S2S_PORT }; if (cluster.isMaster) { var statsWorker = null, serviceWorkers = [], appWorkers = [], userWorkers = []; console.log("The web UI will be on http://localhost:%d/", opts.STATS_WEBUI_PORT); console.log("You have 5 seconds to abort..."); function countdown(n) { if (n >= 1) { console.log("%d...", n); setTimeout(function() { countdown(n-1); }, 1000); } else { console.log("This will get a bit verbose..."); setTimeout(start, 1000); } } countdown(5); function start() { statsWorker = cluster.fork({statsServer: true}); services.forEach(function(service) { serviceWorkers.push(cluster.fork({service: service.port})); }); apps.forEach(function(port) { appWorkers.push(cluster.fork({app: port})); }); for (var i = 0; i < opts.USER_WORKERS; i++) { userWorkers.push(cluster.fork()); } statsWorker.send('start'); serviceWorkers.forEach(function(worker) { worker.send('start'); }); appWorkers.forEach(function(worker) { worker.send({ msg: 'start', config: {services: services, statsPort: statsServer.ioPort} }); }); userWorkers.forEach(function(worker) { worker.send('start'); }); } } else { if (process.env.statsServer) { var server = new Stats(statsServer); process.on('message', function(msg) { if (msg == 'start') { //server.start(); } }); } else if (process.env.service) { var service = new Service(parseInt(process.env.service)); process.on('message', function(msg) { if (msg == 'start') { service.start(); } }); } else if (process.env.app) { var app = new App(parseInt(process.env.app)); process.on('message', function(msg) { if (msg.msg == 'start') { app.configure(msg.config); app.start(); } }); } else { var user = new EndUser(apps); process.on('message', function(msg) { if (msg == 'start') { user.start({ users: opts.USERS_PER_WORKER, minSleep: opts.USERS_MIN_SLEEP, maxSleep: opts.USERS_MAX_SLEEP }); } }); } }