UNPKG

slavery-js

Version:

A simple clustering app that allows you to scale an application on multiple thread, containers or machines

1 lines 6.72 kB
{"version":3,"sources":["../../src/service/RequestQueue.ts"],"sourcesContent":["import { await_interval, Queue, log } from '../utils/index.js';\nimport type { Request } from './types/index.js';\n\nclass RequestQueue {\n /* This class will keep track of all the requests that are made to the service,\n * how long each request takes to be processed,\n * how many requests are in the queue,\n * when the requests are being processed, and\n * request individually.\n */\n\n private queue: Queue<Request> = new Queue();\n private process_request: Function;\n private get_slave: Function;\n private isRunning: boolean = false;\n private interval: NodeJS.Timeout;\n private heartbeat = 100; // Check every 100ms if the request is completed\n private turnover_times: number[] = []; // Stores time taken for the last 500 requests\n private MAX_TURNOVER_ENTRIES = 500; // Limit storage to last 500 requests\n\n constructor({ process_request, get_slave }: { process_request: Function, get_slave: Function }) {\n /*\n * Set an interval to check if there are items in the queue.\n * If there are, pop the first element and process it.\n * If there are no elements, wait for the next element to be added.\n */\n // set functions\n this.process_request = process_request;\n this.get_slave = get_slave;\n if (!this.process_request) throw new Error('Process request cannot be null');\n if (!this.get_slave) throw new Error('Get slave cannot be null');\n // run interval\n this.interval = setInterval(async () => {\n // do not run another function if the previous one is still running\n if (this.isRunning) return;\n // if there are no items in the queue\n if (this.queue.size() === 0) { \n this.isRunning = false;\n return;\n }\n // start the request function\n this.isRunning = true;\n // get the first request from queue\n let request = this.queue.pop();\n if(request === false) throw new Error('Request is null... is the request queue empty?');\n // get a slave to process the request\n const slave = await this.get_slave(request.selector);\n // process the request\n let startTime = Date.now();\n let endTime : number;\n // set running as false\n this.isRunning = false;\n // process the request\n this.process_request(slave, request).then(\n (result: any) => { // record the time\n if(!request) throw new Error('Request is false... is the request queue empty?');\n endTime = Date.now();\n // add values to the request\n request.completed = true;\n request.result = result;\n // Track the time taken for this request\n const timeTaken = endTime - startTime;\n //log(`[RequestQueue] Request completed in ${timeTaken}ms`);\n this.turnover_times.push(timeTaken);\n // Keep only the last 500 entries\n if (this.turnover_times.length > this.MAX_TURNOVER_ENTRIES) \n this.turnover_times.shift(); // Remove the oldest entry\n }\n ).catch((err : any) => {\n console.error('[RequestQueue] Request failed to complete');\n console.error(err);\n return err;\n });\n }, 100);\n }\n\n public addRequest(request: Request): Promise<any> {\n // Add request to the queue and return a promise\n // that will be resolved when the request is completed\n return new Promise(async (resolve, reject) => {\n this.queue.push(request);\n // Wait until the request is completed, or 60 minutes\n await await_interval(() => {\n log(request);\n return request.completed === true;\n }, 60 * 60 * 1000, this.heartbeat)\n .catch(err => {\n console.error('[RequestQueue] Request failed to complete');\n console.error(err);\n reject(err)\n });\n // Resolve the promise with the result of the request\n resolve(request.result);\n });\n }\n\n public queueSize() : number {\n return this.queue.size();\n }\n\n public getTurnoverRatio(): number {\n if (this.turnover_times.length === 0) return 0;\n const sum = this.turnover_times.reduce((acc, time) => acc + time, 0);\n return sum / this.turnover_times.length;\n }\n\n public exit() {\n this.queue.clear();\n clearInterval(this.interval);\n\n }\n}\n\nexport default RequestQueue;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2C;AAG3C,MAAM,aAAa;AAAA;AAAA,EAiBf,YAAY,EAAE,iBAAiB,UAAU,GAAuD;AAThG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAQ,SAAwB,IAAI,mBAAM;AAC1C,wBAAQ;AACR,wBAAQ;AACR,wBAAQ,aAAqB;AAC7B,wBAAQ;AACR,wBAAQ,aAAY;AACpB;AAAA,wBAAQ,kBAA2B,CAAC;AACpC;AAAA,wBAAQ,wBAAuB;AAS3B,SAAK,kBAAkB;AACvB,SAAK,YAAY;AACjB,QAAI,CAAC,KAAK,gBAAiB,OAAM,IAAI,MAAM,gCAAgC;AAC3E,QAAI,CAAC,KAAK,UAAW,OAAM,IAAI,MAAM,0BAA0B;AAE/D,SAAK,WAAW,YAAY,YAAY;AAEpC,UAAI,KAAK,UAAW;AAEpB,UAAI,KAAK,MAAM,KAAK,MAAM,GAAG;AACzB,aAAK,YAAY;AACjB;AAAA,MACJ;AAEA,WAAK,YAAY;AAEjB,UAAI,UAAU,KAAK,MAAM,IAAI;AAC7B,UAAG,YAAY,MAAO,OAAM,IAAI,MAAM,gDAAgD;AAEtF,YAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,QAAQ;AAEnD,UAAI,YAAY,KAAK,IAAI;AACzB,UAAI;AAEJ,WAAK,YAAY;AAEjB,WAAK,gBAAgB,OAAO,OAAO,EAAE;AAAA,QACjC,CAAC,WAAgB;AACb,cAAG,CAAC,QAAS,OAAM,IAAI,MAAM,iDAAiD;AAC9E,oBAAU,KAAK,IAAI;AAEnB,kBAAQ,YAAY;AACpB,kBAAQ,SAAS;AAEjB,gBAAM,YAAY,UAAU;AAE5B,eAAK,eAAe,KAAK,SAAS;AAElC,cAAI,KAAK,eAAe,SAAS,KAAK;AAClC,iBAAK,eAAe,MAAM;AAAA,QAClC;AAAA,MACJ,EAAE,MAAM,CAAC,QAAc;AACnB,gBAAQ,MAAM,2CAA2C;AACzD,gBAAQ,MAAM,GAAG;AACjB,eAAO;AAAA,MACX,CAAC;AAAA,IACL,GAAG,GAAG;AAAA,EACV;AAAA,EAEO,WAAW,SAAgC;AAG9C,WAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAC1C,WAAK,MAAM,KAAK,OAAO;AAEvB,gBAAM,6BAAe,MAAM;AACvB,8BAAI,OAAO;AACX,eAAO,QAAQ,cAAc;AAAA,MACjC,GAAG,KAAK,KAAK,KAAM,KAAK,SAAS,EAChC,MAAM,SAAO;AACV,gBAAQ,MAAM,2CAA2C;AACzD,gBAAQ,MAAM,GAAG;AACjB,eAAO,GAAG;AAAA,MACd,CAAC;AAED,cAAQ,QAAQ,MAAM;AAAA,IAC1B,CAAC;AAAA,EACL;AAAA,EAEO,YAAqB;AACxB,WAAO,KAAK,MAAM,KAAK;AAAA,EAC3B;AAAA,EAEO,mBAA2B;AAC9B,QAAI,KAAK,eAAe,WAAW,EAAG,QAAO;AAC7C,UAAM,MAAM,KAAK,eAAe,OAAO,CAAC,KAAK,SAAS,MAAM,MAAM,CAAC;AACnE,WAAO,MAAM,KAAK,eAAe;AAAA,EACrC;AAAA,EAEO,OAAO;AACV,SAAK,MAAM,MAAM;AACjB,kBAAc,KAAK,QAAQ;AAAA,EAE/B;AACJ;AAEA,IAAO,uBAAQ;","names":[]}