| 1 | export default class TaskQueue { |
| 2 | constructor( |
| 3 | maxTasksPerSecond = 4, |
| 4 | maxSimultaneousTasks = 8, |
| 5 | maxQueueLength = 20 |
| 6 | ) { |
| 7 | this.maxTasksPerSecond = maxTasksPerSecond; |
| 8 | this.maxQueueLength = maxQueueLength; |
| 9 | this.maxSimultaneousTasks = maxSimultaneousTasks; |
| 10 | this.queue = []; |
| 11 | this.processing = false; |
| 12 | this.lastProcessTime = 0; |
| 13 | this.taskCount = 0; |
| 14 | this.tasksWaiting = 0; |
| 15 | } |
| 16 | |
| 17 | async enqueue(taskFunction, that = this, ...args) { |
| 18 | return new Promise((resolve, reject) => { |
| 19 | if (this.queue.length >= this.maxQueueLength) { |
| 20 | reject(new Error("Queue is full. Maximum queue size exceeded.")); |
| 21 | return; |
| 22 | } |
| 23 | this.queue.push({ |
| 24 | taskFunction, |
| 25 | that, |
| 26 | args, |
| 27 | resolve, |
| 28 | reject, |
| 29 | }); |
| 30 | |
| 31 | if (!this.processing) { |
| 32 | this.processQueue(); |
| 33 | } |
| 34 | }); |
| 35 | } |
| 36 | |
| 37 | async processQueue() { |
| 38 | if (this.processing || this.queue.length === 0) { |
| 39 | return; |
| 40 | } |
| 41 | |
| 42 | this.processing = true; |
| 43 | |
| 44 | while (this.queue.length > 0) { |
| 45 | const now = Date.now(); |
| 46 | |
| 47 | if (now - this.lastProcessTime >= 1000) { |
| 48 | this.taskCount = 0; |
| 49 | this.lastProcessTime = now; |
| 50 | } |
| 51 | |
| 52 | if ( |
| 53 | this.taskCount >= this.maxTasksPerSecond || |
| 54 | this.tasksWaiting >= this.maxSimultaneousTasks |
| 55 | ) { |
| 56 | const waitTime = 1000 - (now - this.lastProcessTime); |
| 57 | await this.sleep(waitTime); |
| 58 | continue; |
| 59 | } |
| 60 |
nothing calls this directly
no outgoing calls
no test coverage detected