leaky-bucket-queue
Version:
An implementation of burstable throtling algorithm on top of rxjs
97 lines • 3.55 kB
JavaScript
import { timer, Subject, } from 'rxjs';
import { ArgumentError } from './ArgumentError';
/**
* This queue is a simple implementation of leaky bucket algorithm, in terms of number of emitted
* object. The burst object will by default emitted synchronously.
* @public
*/
var LeakyBucketQueue = /** @class */ (function () {
function LeakyBucketQueue(option) {
this.option = option;
this.bucket = 3;
this.subject = new Subject();
this.queue = [];
this.timerStarted = false;
this.assertOption(option);
this.bucket = option.burstSize;
}
LeakyBucketQueue.prototype.assertOption = function (option) {
if (!option) {
throw ArgumentError.createFromArgumentName('option', 'not be null or undefined');
}
this.assertValue('burstSize', option.burstSize);
this.assertValue('period', option.period);
};
LeakyBucketQueue.prototype.assertValue = function (name, value) {
if (typeof value !== 'number') {
throw ArgumentError.createFromArgumentName(name, 'exist and be a number');
}
if (value < 0) {
throw ArgumentError.createFromArgumentName(name, 'be larger than 0');
}
};
LeakyBucketQueue.prototype.consume = function () {
return this.subject.asObservable();
};
/**
* Queues data for emit at scheduled time. By default burst will be emitted synchronously. If
* consistency is desired (emit item like the delayed item, asynchronously), then a scheduler
* could be used to override this behaviour.
* @param data - data to be queued
*/
LeakyBucketQueue.prototype.enqueue = function (data) {
var _this = this;
this.queue.push(data);
var _loop_1 = function () {
this_1.bucket--;
var data_1 = this_1.queue.shift();
if (this_1.option.scheduler) {
this_1.option.scheduler.schedule(function () { return _this.subject.next(data_1); });
}
else {
this_1.subject.next(data_1);
}
};
var this_1 = this;
while (this.bucket > 0 && this.queue[0]) {
_loop_1();
}
this.startTimer();
};
/** @internal */
LeakyBucketQueue.prototype.startTimer = function () {
var _this = this;
if (this.timerStarted) {
return;
}
this.timer = timer(this.option.period, this.option.period).subscribe({
next: function () {
var data = _this.queue.shift();
if (data) {
_this.subject.next(data);
}
else {
_this.bucket++;
}
if (_this.bucket === _this.option.burstSize && _this.timer) {
_this.timer.unsubscribe();
_this.timer = undefined;
_this.timerStarted = false;
}
},
});
this.timerStarted = true;
};
/**
* Stops the leaky bucket timer and return remaining item on queue for persistence or clean up.
*/
LeakyBucketQueue.prototype.stop = function () {
if (this.timer) {
this.timer.unsubscribe();
}
return this.queue;
};
return LeakyBucketQueue;
}());
export { LeakyBucketQueue };
//# sourceMappingURL=LeakyBucketQueue.js.map