slavery-js
Version:
A simple clustering app that allows you to scale an application on multiple thread, containers or machines
1 lines • 8.55 kB
Source Map (JSON)
{"version":3,"sources":["../../src/service/ProcessBalancer.ts"],"sourcesContent":["import os from 'os';\nimport { log } from '../utils/index.js';\n\ninterface balancerConfig {\n minSlaves?: number;\n maxSlaves?: number;\n queueScaleUpThreshold?: number;\n queueScaleDownThreshold?: number;\n maxIdleRateThreshold?: number;\n minIdleRateThreshold?: number;\n cpuThreshold?: number;\n memThreshold?: number;\n checkInterval?: number;\n checkSlaves: (() => { idleCount: number | undefined, workingCount:number | undefined }) | undefined;\n checkQueueSize: (() => number) | undefined;\n addSlave: (() => void) | undefined;\n removeSlave: (() => void) | undefined;\n}\n\nclass ProcessBalancer {\n private prevQueueSize: number = 0;\n private interval: NodeJS.Timeout | undefined;\n private queueScaleUpThreshold: number;\n private queueScaleDownThreshold: number;\n private maxIdleRateThreshold: number;\n private minIdleRateThreshold: number;\n private cpuThreshold: number;\n private memThreshold: number;\n private checkInterval: number;\n private checkQueueSize: (() => number) | undefined;\n private checkSlaves: (() => { idleCount: number | undefined, workingCount:number | undefined }) | undefined;\n private addSlave: (() => void) | undefined;\n private removeSlave: (() => void) | undefined;\n\n constructor(config: balancerConfig) {\n // if there is at least 3 request in the queue, allow to scale up\n this.queueScaleUpThreshold = config.queueScaleUpThreshold || 3;\n // if there is at most one request on the queue, allow to scale down\n this.queueScaleDownThreshold = config.queueScaleDownThreshold || 0;\n // if we are using a lot of resources, don't scale up\n this.cpuThreshold = config.cpuThreshold || 90;\n this.memThreshold = config.memThreshold || 90;\n // if 80 percent of all slaves are idle, don't allow to make more\n this.maxIdleRateThreshold = config.maxIdleRateThreshold || 0.8\n // if 10 percent of all slaves are idle, don't remove any\n this.minIdleRateThreshold = config.minIdleRateThreshold || 0.1\n // how often do we check\n this.checkInterval = config.checkInterval || 500;\n // function need to check\n this.checkQueueSize = config.checkQueueSize;\n this.checkSlaves = config.checkSlaves;\n this.addSlave = config.addSlave;\n this.removeSlave = config.removeSlave;\n // check if we got all the need callbacks\n this.checkRequiredFunctions();\n // Initialize monitoring\n this.interval = this.startMonitoring();\n }\n\n private getCpuUsage(): number {\n let cpus = os.cpus();\n let totalLoad = cpus.reduce((acc, cpu) => {\n let total = Object.values(cpu.times).reduce((t, v) => t + v, 0);\n return acc + (cpu.times.user / total) * 100;\n }, 0);\n return totalLoad / cpus.length;\n }\n\n private getMemoryUsage(): number {\n return ((os.totalmem() - os.freemem()) / os.totalmem()) * 100;\n }\n\n private monitorSystem(): void {\n if(this.checkQueueSize === undefined) throw Error('checkQueueSize is undefined');\n if(this.checkSlaves === undefined) throw Error('checkSlaves is undefined');\n\n this.checkRequiredFunctions();\n const queueSize = this.checkQueueSize();\n const { idleCount, workingCount } = this.checkSlaves();\n if(idleCount === undefined || workingCount === undefined)\n throw new Error('checkSlaves function returned idleCount or workingCount with value of undefined')\n const idleRate = idleCount / workingCount + idleCount\n const queueGrowth = queueSize - this.prevQueueSize;\n this.prevQueueSize = queueSize;\n const avgCpu = this.getCpuUsage();\n const avgMem = this.getMemoryUsage();\n\n /*\n log(`[ProcessBalancer]\n Queue Size: ${queueSize},\n Growth: ${queueGrowth},\n CPU: ${avgCpu.toFixed(2)}%,\n MEM: ${avgMem.toFixed(2)}%,\n Idle Slaves: ${idleCount},\n Working Slaves: ${workingCount},\n Total Slaves: ${idleCount + workingCount},\n Idle Ratio: ${(idleCount / workingCount).toFixed(2)}`\n );\n */\n\n if (\n // if the queue size is passed a threshold: 3\n queueSize > this.queueScaleUpThreshold &&\n // and it is growing\n queueGrowth > 0 &&\n // and the average CPU and MEM usage is below 90%\n avgCpu < this.cpuThreshold &&\n avgMem < this.memThreshold &&\n // and the ratio of idle slaves to working slaves is greater than than threshold\n idleRate < this.maxIdleRateThreshold\n ){\n log('Scaling up, adding a node');\n //@ts-ignore\n this.addSlave();\n }\n if ( // if the queue size is less than or equal to the threshold\n queueSize <= this.queueScaleDownThreshold &&\n // if there is at least one\n idleCount > 1 &&\n // if the queue size is degreesing or not growing\n queueGrowth <= 0 &&\n // if the idle rate is low\n idleRate > this.minIdleRateThreshold\n ){\n log('Scaling down, removing a node');\n //@ts-ignore\n this.removeSlave();\n }\n }\n\n private startMonitoring(): NodeJS.Timeout {\n return setInterval(() => {\n this.monitorSystem();\n }, this.checkInterval);\n }\n\n private checkRequiredFunctions(): void {\n if (this.checkQueueSize === undefined)\n throw new Error('Missing required function checkQueueSize in config');\n if (this.checkSlaves === undefined)\n throw new Error('Missing required function checkSlaves in config');\n if (this.addSlave === undefined)\n throw new Error('Missing required function addSlave in config');\n if (this.removeSlave === undefined)\n throw new Error('Missing required function removeSlave in config');\n }\n\n public exit(): void {\n // end monitoring\n clearInterval(this.interval);\n }\n}\n\nexport default ProcessBalancer;\n"],"mappings":"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","names":["os"]}