352 lines
11 KiB
JavaScript
352 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
|
|
|
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
|
|
|
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
|
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
|
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
|
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
|
|
var BottleneckError, IORedisConnection, RedisConnection, RedisDatastore, parser;
|
|
parser = require("./parser");
|
|
BottleneckError = require("./BottleneckError");
|
|
RedisConnection = require("./RedisConnection");
|
|
IORedisConnection = require("./IORedisConnection");
|
|
RedisDatastore = class RedisDatastore {
|
|
constructor(instance, storeOptions, storeInstanceOptions) {
|
|
this.instance = instance;
|
|
this.storeOptions = storeOptions;
|
|
this.originalId = this.instance.id;
|
|
this.clientId = this.instance._randomIndex();
|
|
parser.load(storeInstanceOptions, storeInstanceOptions, this);
|
|
this.clients = {};
|
|
this.capacityPriorityCounters = {};
|
|
this.sharedConnection = this.connection != null;
|
|
|
|
if (this.connection == null) {
|
|
this.connection = this.instance.datastore === "redis" ? new RedisConnection({
|
|
Redis: this.Redis,
|
|
clientOptions: this.clientOptions,
|
|
Promise: this.Promise,
|
|
Events: this.instance.Events
|
|
}) : this.instance.datastore === "ioredis" ? new IORedisConnection({
|
|
Redis: this.Redis,
|
|
clientOptions: this.clientOptions,
|
|
clusterNodes: this.clusterNodes,
|
|
Promise: this.Promise,
|
|
Events: this.instance.Events
|
|
}) : void 0;
|
|
}
|
|
|
|
this.instance.connection = this.connection;
|
|
this.instance.datastore = this.connection.datastore;
|
|
this.ready = this.connection.ready.then(clients => {
|
|
this.clients = clients;
|
|
return this.runScript("init", this.prepareInitSettings(this.clearDatastore));
|
|
}).then(() => {
|
|
return this.connection.__addLimiter__(this.instance);
|
|
}).then(() => {
|
|
return this.runScript("register_client", [this.instance.queued()]);
|
|
}).then(() => {
|
|
var base;
|
|
|
|
if (typeof (base = this.heartbeat = setInterval(() => {
|
|
return this.runScript("heartbeat", []).catch(e => {
|
|
return this.instance.Events.trigger("error", e);
|
|
});
|
|
}, this.heartbeatInterval)).unref === "function") {
|
|
base.unref();
|
|
}
|
|
|
|
return this.clients;
|
|
});
|
|
}
|
|
|
|
__publish__(message) {
|
|
var _this = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
var client;
|
|
|
|
var _ref = yield _this.ready;
|
|
|
|
client = _ref.client;
|
|
return client.publish(_this.instance.channel(), `message:${message.toString()}`);
|
|
})();
|
|
}
|
|
|
|
onMessage(channel, message) {
|
|
var _this2 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
var capacity, counter, data, drained, e, newCapacity, pos, priorityClient, rawCapacity, type;
|
|
|
|
try {
|
|
pos = message.indexOf(":");
|
|
var _ref2 = [message.slice(0, pos), message.slice(pos + 1)];
|
|
type = _ref2[0];
|
|
data = _ref2[1];
|
|
|
|
if (type === "capacity") {
|
|
return yield _this2.instance._drainAll(data.length > 0 ? ~~data : void 0);
|
|
} else if (type === "capacity-priority") {
|
|
var _data$split = data.split(":");
|
|
|
|
var _data$split2 = _slicedToArray(_data$split, 3);
|
|
|
|
rawCapacity = _data$split2[0];
|
|
priorityClient = _data$split2[1];
|
|
counter = _data$split2[2];
|
|
capacity = rawCapacity.length > 0 ? ~~rawCapacity : void 0;
|
|
|
|
if (priorityClient === _this2.clientId) {
|
|
drained = yield _this2.instance._drainAll(capacity);
|
|
newCapacity = capacity != null ? capacity - (drained || 0) : "";
|
|
return yield _this2.clients.client.publish(_this2.instance.channel(), `capacity-priority:${newCapacity}::${counter}`);
|
|
} else if (priorityClient === "") {
|
|
clearTimeout(_this2.capacityPriorityCounters[counter]);
|
|
delete _this2.capacityPriorityCounters[counter];
|
|
return _this2.instance._drainAll(capacity);
|
|
} else {
|
|
return _this2.capacityPriorityCounters[counter] = setTimeout(
|
|
/*#__PURE__*/
|
|
_asyncToGenerator(function* () {
|
|
var e;
|
|
|
|
try {
|
|
delete _this2.capacityPriorityCounters[counter];
|
|
yield _this2.runScript("blacklist_client", [priorityClient]);
|
|
return yield _this2.instance._drainAll(capacity);
|
|
} catch (error) {
|
|
e = error;
|
|
return _this2.instance.Events.trigger("error", e);
|
|
}
|
|
}), 1000);
|
|
}
|
|
} else if (type === "message") {
|
|
return _this2.instance.Events.trigger("message", data);
|
|
} else if (type === "blocked") {
|
|
return yield _this2.instance._dropAllQueued();
|
|
}
|
|
} catch (error) {
|
|
e = error;
|
|
return _this2.instance.Events.trigger("error", e);
|
|
}
|
|
})();
|
|
}
|
|
|
|
__disconnect__(flush) {
|
|
clearInterval(this.heartbeat);
|
|
|
|
if (this.sharedConnection) {
|
|
return this.connection.__removeLimiter__(this.instance);
|
|
} else {
|
|
return this.connection.disconnect(flush);
|
|
}
|
|
}
|
|
|
|
runScript(name, args) {
|
|
var _this3 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
if (!(name === "init" || name === "register_client")) {
|
|
yield _this3.ready;
|
|
}
|
|
|
|
return new _this3.Promise((resolve, reject) => {
|
|
var all_args, arr;
|
|
all_args = [Date.now(), _this3.clientId].concat(args);
|
|
|
|
_this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args);
|
|
|
|
arr = _this3.connection.__scriptArgs__(name, _this3.originalId, all_args, function (err, replies) {
|
|
if (err != null) {
|
|
return reject(err);
|
|
}
|
|
|
|
return resolve(replies);
|
|
});
|
|
return _this3.connection.__scriptFn__(name)(...arr);
|
|
}).catch(e => {
|
|
if (e.message === "SETTINGS_KEY_NOT_FOUND") {
|
|
if (name === "heartbeat") {
|
|
return _this3.Promise.resolve();
|
|
} else {
|
|
return _this3.runScript("init", _this3.prepareInitSettings(false)).then(() => {
|
|
return _this3.runScript(name, args);
|
|
});
|
|
}
|
|
} else if (e.message === "UNKNOWN_CLIENT") {
|
|
return _this3.runScript("register_client", [_this3.instance.queued()]).then(() => {
|
|
return _this3.runScript(name, args);
|
|
});
|
|
} else {
|
|
return _this3.Promise.reject(e);
|
|
}
|
|
});
|
|
})();
|
|
}
|
|
|
|
prepareArray(arr) {
|
|
var i, len, results, x;
|
|
results = [];
|
|
|
|
for (i = 0, len = arr.length; i < len; i++) {
|
|
x = arr[i];
|
|
results.push(x != null ? x.toString() : "");
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
prepareObject(obj) {
|
|
var arr, k, v;
|
|
arr = [];
|
|
|
|
for (k in obj) {
|
|
v = obj[k];
|
|
arr.push(k, v != null ? v.toString() : "");
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
|
|
prepareInitSettings(clear) {
|
|
var args;
|
|
args = this.prepareObject(Object.assign({}, this.storeOptions, {
|
|
id: this.originalId,
|
|
version: this.instance.version,
|
|
groupTimeout: this.timeout,
|
|
clientTimeout: this.clientTimeout
|
|
}));
|
|
args.unshift(clear ? 1 : 0, this.instance.version);
|
|
return args;
|
|
}
|
|
|
|
convertBool(b) {
|
|
return !!b;
|
|
}
|
|
|
|
__updateSettings__(options) {
|
|
var _this4 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
yield _this4.runScript("update_settings", _this4.prepareObject(options));
|
|
return parser.overwrite(options, options, _this4.storeOptions);
|
|
})();
|
|
}
|
|
|
|
__running__() {
|
|
return this.runScript("running", []);
|
|
}
|
|
|
|
__queued__() {
|
|
return this.runScript("queued", []);
|
|
}
|
|
|
|
__done__() {
|
|
return this.runScript("done", []);
|
|
}
|
|
|
|
__groupCheck__() {
|
|
var _this5 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
return _this5.convertBool((yield _this5.runScript("group_check", [])));
|
|
})();
|
|
}
|
|
|
|
__incrementReservoir__(incr) {
|
|
return this.runScript("increment_reservoir", [incr]);
|
|
}
|
|
|
|
__currentReservoir__() {
|
|
return this.runScript("current_reservoir", []);
|
|
}
|
|
|
|
__check__(weight) {
|
|
var _this6 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
return _this6.convertBool((yield _this6.runScript("check", _this6.prepareArray([weight]))));
|
|
})();
|
|
}
|
|
|
|
__register__(index, weight, expiration) {
|
|
var _this7 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
var reservoir, success, wait;
|
|
|
|
var _ref4 = yield _this7.runScript("register", _this7.prepareArray([index, weight, expiration]));
|
|
|
|
var _ref5 = _slicedToArray(_ref4, 3);
|
|
|
|
success = _ref5[0];
|
|
wait = _ref5[1];
|
|
reservoir = _ref5[2];
|
|
return {
|
|
success: _this7.convertBool(success),
|
|
wait,
|
|
reservoir
|
|
};
|
|
})();
|
|
}
|
|
|
|
__submit__(queueLength, weight) {
|
|
var _this8 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
var blocked, e, maxConcurrent, overweight, reachedHWM, strategy;
|
|
|
|
try {
|
|
var _ref6 = yield _this8.runScript("submit", _this8.prepareArray([queueLength, weight]));
|
|
|
|
var _ref7 = _slicedToArray(_ref6, 3);
|
|
|
|
reachedHWM = _ref7[0];
|
|
blocked = _ref7[1];
|
|
strategy = _ref7[2];
|
|
return {
|
|
reachedHWM: _this8.convertBool(reachedHWM),
|
|
blocked: _this8.convertBool(blocked),
|
|
strategy
|
|
};
|
|
} catch (error) {
|
|
e = error;
|
|
|
|
if (e.message.indexOf("OVERWEIGHT") === 0) {
|
|
var _e$message$split = e.message.split(":");
|
|
|
|
var _e$message$split2 = _slicedToArray(_e$message$split, 3);
|
|
|
|
overweight = _e$message$split2[0];
|
|
weight = _e$message$split2[1];
|
|
maxConcurrent = _e$message$split2[2];
|
|
throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${maxConcurrent}`);
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
})();
|
|
}
|
|
|
|
__free__(index, weight) {
|
|
var _this9 = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
var running;
|
|
running = yield _this9.runScript("free", _this9.prepareArray([index]));
|
|
return {
|
|
running
|
|
};
|
|
})();
|
|
}
|
|
|
|
};
|
|
module.exports = RedisDatastore; |