I implemented a simple queuing system for my Node.JS app and wanted a critique on it's structure.
const TPS = 20;
const Queue = {
counter: 1,
items: {},
/**
* Add an item to the queue, with the given func to call
* @param {Function} func
* @param {Boolean} repeating
* @return {Number}
*/
add(func, repeating = false) {
const id = this.counter++;
this.items[id] = {func, repeating, id};
return id;
},
/**
* Remove an item from the queue with the given id
* @param {Number} id
*/
remove(id) {
if (this.items.hasOwnProperty(id)) {
delete this.items[id];
}
},
/**
* Process items in the queue
*/
process() {
for (let id in this.items) {
// Prevent this item from being processed again
if (!this.items.hasOwnProperty(id) || this.items[id].processing) {
continue;
}
// Delete this item when it's scheduled for deletion
if (this.items[id].scheduledForDeletion) {
delete this.items[id];
continue;
}
// Let the queue know this item is being processed and
// it's scheduled deletion status
this.items[id].processing = true;
this.items[id].scheduledForDeletion = !this.items[id].repeating;
// Don't wait for item's promise to resolve, since this
// will create a backlog on the queue
(async () => {
try {
await this.items[id].func.call(null);
} catch (err) {
// TODO: Handle errors.
console.error(err);
}
this.items[id].processing = false;
})();
}
}
};
(function tick() {
setTimeout(tick, 1000 / TPS);
Queue.process();
})();
This is an example of how it's implemented.
// Add three items to the queue: 1 normal, 1 async and 1 repeating
Queue.add(() => console.info(`[tick] -> ${Date.now()}`));
Queue.add(async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100));
const timeLoop = Queue.add(() => console.info(`[loop] time (loop) -> ${Date.now()}`), true);
// Remove the looping item from the queue
setTimeout(() => Queue.remove(timeLoop), 500);
The idea is to have this run when the server starts and continually process the queue items. Queue is in it's own file and exported. I import this file into my controllers and call (for example) Queue.add('function to add user to DB and send out email')
.
process
; andasync
atQueue.add(async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100))
where noPromise
is included within or returned from the function passed toQueue.add()
? IsQueue.add()
andprocess
expected to handle both asynchronous and synchronous functions as parameters? \$\endgroup\$ – guest271314 Dec 1 '18 at 1:33await
keyword needs to be inside anasync
body, but I think it might be better to move it to the process function definition likeasync process()
. TheQueue.add
calls at the end of my code are just examples to show you that you can add async items to the queue. And actuallyasync
returns a promise by default so technically they are returning promises. Finally, yes, the process method handles both sync and async items. \$\endgroup\$ – Enijar Dec 1 '18 at 16:05async () => setTimeout(() => console.info(`[async] -> ${Date.now()}`), 100)
return any value? See Why is value undefined at .then() chained to Promise? \$\endgroup\$ – guest271314 Dec 1 '18 at 19:52