UNPKG

slavery-js

Version:

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

1 lines 9.74 kB
{"version":3,"sources":["../../src/service/RequestQueue.ts"],"sourcesContent":["import type { Request } from './types/index.js';\n\ntype RequestQueueOptions = {\n heartbeat?: number;\n requestTimeout?: number; // Timeout for requests\n onError?: 'throw' | 'return' | 'log' | 'ignore';\n}\n\ntype RequestQueueParameters = {\n process_request: Function;\n get_slave: Function;\n options?: RequestQueueOptions;\n}\n\ntype addRequestParameters = {\n method: string;\n type: 'run' | 'exec';\n parameters: any;\n selector: string;\n}\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: Request[] = [];\n private process_request: Function;\n private currentId: number = 0;\n private get_slave: Function;\n private isIntervalRunning: boolean = false;\n private interval: NodeJS.Timeout;\n private heartbeat;\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 private requestTimeout: number; // Timeout for requests\n\n constructor({ process_request, get_slave, options }: RequestQueueParameters) {\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 // process wrapper for maintainig the request\n this.process_request = async (slave: any, request: Request) => {\n let result = await process_request(slave, request);\n return { result, id: request.id }\n }\n this.get_slave = get_slave;\n this.heartbeat = options?.heartbeat || 10; // Check every 10ms if the request is completed\n this.requestTimeout = options?.requestTimeout || 5 * 60 * 1000; // Default timeout is 5 minutes\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.isIntervalRunning) return;\n // if there are no items in the queue\n if (this.queue.length === 0){\n this.isIntervalRunning = false;\n return;\n }\n // start the request function\n this.isIntervalRunning = true;\n // start to look at the queue\n for (let request of this.queue) {\n if(request.completed){\n // remove the request at the index\n this.queue = this.queue.filter((r) => r.id !== request.id);\n request.onComplete();\n this.isIntervalRunning = false;\n // get the turnover time\n this.addTurnOverTime(request.startTime);\n return;\n }else if(request.isProcessing){\n // if check if the request has timed out\n if(Date.now() - request.startTime > this.requestTimeout){\n request.completed = true;\n request.result = {\n isError: true,\n error: new Error(`slavery-js: Request '${request.method}', timed out after: ${this.requestTimeout}. You can change this behavior by setting the 'timeout', and 'onError' in the options at slavery({})`),\n }\n }\n }else{ // if the is neither completed nor processing\n request.isProcessing = true;\n // get slave\n const slave = await this.get_slave(request.selector);\n this.isIntervalRunning = false;\n // process the request\n this.process_request(slave, request)\n .then(({ result, id }: { result: any, id: number }) => {\n let request = this.getRequest(id);\n if(request){ // complete the request\n request.completed = true;\n request.result = result;\n }\n })\n .catch((err : any) => {\n throw new Error('slavery-js [RequestQueue]: this Error should not be reachable, please report this issue', err);\n })\n }\n }\n this.isIntervalRunning = false;\n }, this.heartbeat);\n }\n\n\n public addRequest( { method, type, parameters, selector }: addRequestParameters ): 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 => {\n // is id has reached the max value, reset it to 0\n if(this.currentId >= Number.MAX_SAFE_INTEGER) this.currentId = 0;\n let request: Request = {\n id: ++this.currentId,\n method: method,\n type: type,\n parameters: parameters,\n selector: selector || undefined,\n completed: false,\n isProcessing: false,\n onComplete: () => { \n resolve(request.result)\n },\n startTime: Date.now(),\n result: null,\n };\n // add the request to the queue\n this.queue.push(request);\n });\n }\n\n private getRequest(id: number): Request | null {\n // Get request by id\n const request = this.queue.find(r => r.id === id);\n if (request) {\n return request;\n } else {\n return null;\n }\n \n }\n\n\n\n private addTurnOverTime(startTime: number){\n const timeTaken = Date.now() - startTime;\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\n\n public queueSize() : number {\n return this.queue.length;\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 getTurnoverTimes(): number[] {\n return this.turnover_times;\n }\n\n public exit() {\n this.queue = [];\n clearInterval(this.interval);\n\n }\n}\n\nexport default RequestQueue;\n"],"mappings":"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","names":["request"]}