Добавлен класс LimitedQueue для организации очередей

This commit is contained in:
Book Pauk
2020-01-26 18:38:09 +07:00
parent a50d61c3ce
commit 3da6befe10

120
server/core/LimitedQueue.js Normal file
View File

@@ -0,0 +1,120 @@
const cleanPeriod = 60*1000;//1 минута
const cleanTimeout = 60;//timeout в минутах (cleanPeriod)
class LimitedQueue {
constructor(enqueueAfter = 10, size = 100, timeout = cleanTimeout) {//timeout в минутах (cleanPeriod)
this.size = size;
this.timeout = timeout;
this.freed = enqueueAfter;
this.listeners = [];
this.timer = setTimeout(() => { this.periodicClean(); }, cleanPeriod);
}
_addListener(listener) {
this.listeners.push(Object.assign({regTime: Date.now()}, listener));
}
//отсылаем сообщение первому ожидающему и удаляем его из списка
_emitFree() {
if (this.listeners.length > 0) {
let listener = this.listeners.shift();
listener.onFree();
const now = Date.now();
for (let i = 0; i < this.listeners.length; i++) {
listener = this.listeners[i];
listener.regTime = now;
listener.onPlaceChange(i + 1);
}
}
}
get(onPlaceChange) {
return new Promise((resolve, reject) => {
if (this.destroyed)
reject('destroyed');
const take = () => {
if (this.freed <= 0)
throw new Error('Ошибка получения ресурсов в очереди ожидания');
this.freed--;
let returned = false;
return {
ret: () => {
if (!returned) {
this.freed++;
this._emitFree();
returned = true;
}
}
};
};
if (this.freed > 0) {
resolve(take());
} else {
if (this.listeners.length < this.size) {
this._addListener({
onFree: () => {
resolve(take());
},
onError: (err) => {
reject(err);
},
onPlaceChange: (i) => {
if (onPlaceChange)
onPlaceChange(i);
}
});
if (onPlaceChange)
onPlaceChange(this.listeners.length);
} else {
reject('Превышен размер очереди ожидания');
}
}
});
}
destroy() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
for (const listener of this.listeners) {
listener.onError('destroy');
}
this.listeners = [];
this.destroyed = true;
}
periodicClean() {
try {
this.timer = null;
const now = Date.now();
//чистка listeners, убираем зависшие в очереди на одном месте
let newListeners = [];
for (const listener of this.listeners) {
if (now - listener.regTime < this.timeout*cleanPeriod - 50) {
newListeners.push(listener);
} else {
listener.onError('Время ожидания в очереди истекло');
}
}
this.listeners = newListeners;
} finally {
if (!this.destroyed) {
this.timer = setTimeout(() => { this.periodicClean(); }, cleanPeriod);
}
}
}
}
module.exports = LimitedQueue;