UNPKG

bottleneck

Version:

Distributed task scheduler and rate limiter

1,341 lines (1,160 loc) 38.1 kB
/** * This file contains the Bottleneck library (MIT), compiled to ES2017, and without Clustering support. * https://github.com/SGrondin/bottleneck */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.Bottleneck = factory()); }(this, (function () { 'use strict'; var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getCjsExportFromNamespace (n) { return n && n.default || n; } var load = function(received, defaults, onto = {}) { var k, ref, v; for (k in defaults) { v = defaults[k]; onto[k] = (ref = received[k]) != null ? ref : v; } return onto; }; var overwrite = function(received, defaults, onto = {}) { var k, v; for (k in received) { v = received[k]; if (defaults[k] !== void 0) { onto[k] = v; } } return onto; }; var parser = { load: load, overwrite: overwrite }; var DLList; DLList = class DLList { constructor(_queues) { this._queues = _queues; this._first = null; this._last = null; this.length = 0; } push(value) { var node, ref1; this.length++; if ((ref1 = this._queues) != null) { ref1.incr(); } node = { value, next: null }; if (this._last != null) { this._last.next = node; this._last = node; } else { this._first = this._last = node; } return void 0; } shift() { var ref1, ref2, value; if (this._first == null) { return void 0; } else { this.length--; if ((ref1 = this._queues) != null) { ref1.decr(); } } value = this._first.value; this._first = (ref2 = this._first.next) != null ? ref2 : (this._last = null); return value; } first() { if (this._first != null) { return this._first.value; } } getArray() { var node, ref, results; node = this._first; results = []; while (node != null) { results.push((ref = node, node = node.next, ref.value)); } return results; } forEachShift(cb) { var node; node = this.shift(); while (node != null) { (cb(node), node = this.shift()); } return void 0; } }; var DLList_1 = DLList; var Events; Events = class Events { constructor(instance) { this.instance = instance; this._events = {}; if ((this.instance.on != null) || (this.instance.once != null) || (this.instance.removeAllListeners != null)) { throw new Error("An Emitter already exists for this object"); } this.instance.on = (name, cb) => { return this._addListener(name, "many", cb); }; this.instance.once = (name, cb) => { return this._addListener(name, "once", cb); }; this.instance.removeAllListeners = (name = null) => { if (name != null) { return delete this._events[name]; } else { return this._events = {}; } }; } _addListener(name, status, cb) { var base; if ((base = this._events)[name] == null) { base[name] = []; } this._events[name].push({cb, status}); return this.instance; } trigger(name, ...args) { if (name !== "debug") { this.trigger("debug", `Event triggered: ${name}`, args); } if (this._events[name] == null) { return; } this._events[name] = this._events[name].filter(function(listener) { return listener.status !== "none"; }); return this._events[name].forEach((listener) => { var e, ret; if (listener.status === "none") { return; } if (listener.status === "once") { listener.status = "none"; } try { ret = typeof listener.cb === "function" ? listener.cb(...args) : void 0; return ret != null ? typeof ret.then === "function" ? ret.then(function() {}).catch((e) => { return this.trigger("error", e); }) : void 0 : void 0; } catch (error) { e = error; { return this.trigger("error", e); } } }); } }; var Events_1 = Events; var DLList$1, Events$1, Queues; DLList$1 = DLList_1; Events$1 = Events_1; Queues = class Queues { constructor(num_priorities) { var i; this.Events = new Events$1(this); this._length = 0; this._lists = (function() { var j, ref, results; results = []; for (i = j = 1, ref = num_priorities; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) { results.push(new DLList$1(this)); } return results; }).call(this); } incr() { if (this._length++ === 0) { return this.Events.trigger("leftzero"); } } decr() { if (--this._length === 0) { return this.Events.trigger("zero"); } } push(priority, job) { return this._lists[priority].push(job); } queued(priority) { if (priority != null) { return this._lists[priority].length; } else { return this._length; } } shiftAll(fn) { return this._lists.forEach(function(list) { return list.forEachShift(fn); }); } getFirst(arr = this._lists) { var j, len, list; for (j = 0, len = arr.length; j < len; j++) { list = arr[j]; if (list.length > 0) { return list; } } return []; } shiftLastFrom(priority) { return this.getFirst(this._lists.slice(priority).reverse()).shift(); } }; var Queues_1 = Queues; var BottleneckError; BottleneckError = class BottleneckError extends Error {}; var BottleneckError_1 = BottleneckError; var BottleneckError$1, LocalDatastore, parser$1; parser$1 = parser; BottleneckError$1 = BottleneckError_1; LocalDatastore = class LocalDatastore { constructor(instance, storeOptions, storeInstanceOptions) { var base; this.instance = instance; this.storeOptions = storeOptions; this.clientId = this.instance._randomIndex(); parser$1.load(storeInstanceOptions, storeInstanceOptions, this); this._nextRequest = this._lastReservoirRefresh = Date.now(); this._running = 0; this._done = 0; this._unblockTime = 0; this.ready = this.yieldLoop(); this.clients = {}; if (typeof (base = (this.heartbeat = setInterval(() => { var now, reservoirRefreshActive; now = Date.now(); reservoirRefreshActive = (this.storeOptions.reservoirRefreshInterval != null) && (this.storeOptions.reservoirRefreshAmount != null); if (reservoirRefreshActive && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; this._lastReservoirRefresh = now; return this.instance._drainAll(this.computeCapacity()); } }, this.heartbeatInterval))).unref === "function") { base.unref(); } } async __publish__(message) { await this.yieldLoop(); return this.instance.Events.trigger("message", message.toString()); } async __disconnect__(flush) { await this.yieldLoop(); clearInterval(this.heartbeat); return this.Promise.resolve(); } yieldLoop(t = 0) { return new this.Promise(function(resolve, reject) { return setTimeout(resolve, t); }); } computePenalty() { var ref; return (ref = this.storeOptions.penalty) != null ? ref : (15 * this.storeOptions.minTime) || 5000; } async __updateSettings__(options) { await this.yieldLoop(); parser$1.overwrite(options, options, this.storeOptions); this.instance._drainAll(this.computeCapacity()); return true; } async __running__() { await this.yieldLoop(); return this._running; } async __done__() { await this.yieldLoop(); return this._done; } async __groupCheck__(time) { await this.yieldLoop(); return (this._nextRequest + this.timeout) < time; } computeCapacity() { var maxConcurrent, reservoir; ({maxConcurrent, reservoir} = this.storeOptions); if ((maxConcurrent != null) && (reservoir != null)) { return Math.min(maxConcurrent - this._running, reservoir); } else if (maxConcurrent != null) { return maxConcurrent - this._running; } else if (reservoir != null) { return reservoir; } else { return null; } } conditionsCheck(weight) { var capacity; capacity = this.computeCapacity(); return (capacity == null) || weight <= capacity; } async __incrementReservoir__(incr) { var reservoir; await this.yieldLoop(); reservoir = this.storeOptions.reservoir += incr; this.instance._drainAll(this.computeCapacity()); return reservoir; } async __currentReservoir__() { await this.yieldLoop(); return this.storeOptions.reservoir; } isBlocked(now) { return this._unblockTime >= now; } check(weight, now) { return this.conditionsCheck(weight) && (this._nextRequest - now) <= 0; } async __check__(weight) { var now; await this.yieldLoop(); now = Date.now(); return this.check(weight, now); } async __register__(index, weight, expiration) { var now, wait; await this.yieldLoop(); now = Date.now(); if (this.conditionsCheck(weight)) { this._running += weight; if (this.storeOptions.reservoir != null) { this.storeOptions.reservoir -= weight; } wait = Math.max(this._nextRequest - now, 0); this._nextRequest = now + wait + this.storeOptions.minTime; return { success: true, wait, reservoir: this.storeOptions.reservoir }; } else { return { success: false }; } } strategyIsBlock() { return this.storeOptions.strategy === 3; } async __submit__(queueLength, weight) { var blocked, now, reachedHWM; await this.yieldLoop(); if ((this.storeOptions.maxConcurrent != null) && weight > this.storeOptions.maxConcurrent) { throw new BottleneckError$1(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${this.storeOptions.maxConcurrent}`); } now = Date.now(); reachedHWM = (this.storeOptions.highWater != null) && queueLength === this.storeOptions.highWater && !this.check(weight, now); blocked = this.strategyIsBlock() && (reachedHWM || this.isBlocked(now)); if (blocked) { this._unblockTime = now + this.computePenalty(); this._nextRequest = this._unblockTime + this.storeOptions.minTime; this.instance._dropAllQueued(); } return { reachedHWM, blocked, strategy: this.storeOptions.strategy }; } async __free__(index, weight) { await this.yieldLoop(); this._running -= weight; this._done += weight; this.instance._drainAll(this.computeCapacity()); return { running: this._running }; } }; var LocalDatastore_1 = LocalDatastore; var BottleneckError$2, States; BottleneckError$2 = BottleneckError_1; States = class States { constructor(status1) { this.status = status1; this.jobs = {}; this.counts = this.status.map(function() { return 0; }); } next(id) { var current, next; current = this.jobs[id]; next = current + 1; if ((current != null) && next < this.status.length) { this.counts[current]--; this.counts[next]++; return this.jobs[id]++; } else if (current != null) { this.counts[current]--; return delete this.jobs[id]; } } start(id) { var initial; initial = 0; this.jobs[id] = initial; return this.counts[initial]++; } remove(id) { var current; current = this.jobs[id]; if (current != null) { this.counts[current]--; delete this.jobs[id]; } return current != null; } jobStatus(id) { var ref; return (ref = this.status[this.jobs[id]]) != null ? ref : null; } statusJobs(status) { var k, pos, ref, results, v; if (status != null) { pos = this.status.indexOf(status); if (pos < 0) { throw new BottleneckError$2(`status must be one of ${this.status.join(', ')}`); } ref = this.jobs; results = []; for (k in ref) { v = ref[k]; if (v === pos) { results.push(k); } } return results; } else { return Object.keys(this.jobs); } } statusCounts() { return this.counts.reduce(((acc, v, i) => { acc[this.status[i]] = v; return acc; }), {}); } }; var States_1 = States; var DLList$2, Sync, splice = [].splice; DLList$2 = DLList_1; Sync = class Sync { constructor(name, Promise) { this.submit = this.submit.bind(this); this.name = name; this.Promise = Promise; this._running = 0; this._queue = new DLList$2(); } isEmpty() { return this._queue.length === 0; } _tryToRun() { var next; if ((this._running < 1) && this._queue.length > 0) { this._running++; next = this._queue.shift(); return next.task(...next.args, (...args) => { this._running--; this._tryToRun(); return typeof next.cb === "function" ? next.cb(...args) : void 0; }); } } submit(task, ...args) { var cb, ref; ref = args, [...args] = ref, [cb] = splice.call(args, -1); this._queue.push({task, args, cb}); return this._tryToRun(); } schedule(task, ...args) { var wrapped; wrapped = function(...args) { var cb, ref; ref = args, [...args] = ref, [cb] = splice.call(args, -1); return (task(...args)).then(function(...args) { return cb(null, ...args); }).catch(function(...args) { return cb(...args); }); }; return new this.Promise((resolve, reject) => { return this.submit(wrapped, ...args, function(...args) { return (args[0] != null ? reject : (args.shift(), resolve))(...args); }); }); } }; var Sync_1 = Sync; var version = "2.14.1"; var version$1 = { version: version }; var version$2 = /*#__PURE__*/Object.freeze({ version: version, default: version$1 }); var require$$2 = () => console.log('You must import the full version of Bottleneck in order to use this feature.'); var require$$3 = () => console.log('You must import the full version of Bottleneck in order to use this feature.'); var require$$4 = () => console.log('You must import the full version of Bottleneck in order to use this feature.'); var Events$2, Group, IORedisConnection$1, RedisConnection$1, Scripts$1, parser$2; parser$2 = parser; Events$2 = Events_1; RedisConnection$1 = require$$2; IORedisConnection$1 = require$$3; Scripts$1 = require$$4; Group = (function() { class Group { constructor(limiterOptions = {}) { this.deleteKey = this.deleteKey.bind(this); this.updateSettings = this.updateSettings.bind(this); this.limiterOptions = limiterOptions; parser$2.load(this.limiterOptions, this.defaults, this); this.Events = new Events$2(this); this.instances = {}; this.Bottleneck = Bottleneck_1; this._startAutoCleanup(); this.sharedConnection = this.connection != null; if (this.connection == null) { if (this.limiterOptions.datastore === "redis") { this.connection = new RedisConnection$1(Object.assign({}, this.limiterOptions, {Events: this.Events})); } else if (this.limiterOptions.datastore === "ioredis") { this.connection = new IORedisConnection$1(Object.assign({}, this.limiterOptions, {Events: this.Events})); } } } key(key = "") { var ref; return (ref = this.instances[key]) != null ? ref : (() => { var limiter; limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { id: `${this.id}-${key}`, timeout: this.timeout, connection: this.connection })); this.Events.trigger("created", limiter, key); return limiter; })(); } async deleteKey(key = "") { var deleted, instance; instance = this.instances[key]; if (this.connection) { deleted = (await this.connection.__runCommand__(['del', ...Scripts$1.allKeys(`${this.id}-${key}`)])); } if (instance != null) { delete this.instances[key]; await instance.disconnect(); } return (instance != null) || deleted > 0; } limiters() { var k, ref, results, v; ref = this.instances; results = []; for (k in ref) { v = ref[k]; results.push({ key: k, limiter: v }); } return results; } keys() { return Object.keys(this.instances); } async clusterKeys() { var cursor, end, found, i, k, keys, len, next, start; if (this.connection == null) { return this.Promise.resolve(this.keys()); } keys = []; cursor = null; start = `b_${this.id}-`.length; end = "_settings".length; while (cursor !== 0) { [next, found] = (await this.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${this.id}-*_settings`, "count", 10000])); cursor = ~~next; for (i = 0, len = found.length; i < len; i++) { k = found[i]; keys.push(k.slice(start, -end)); } } return keys; } _startAutoCleanup() { var base; clearInterval(this.interval); return typeof (base = (this.interval = setInterval(async() => { var e, k, ref, results, time, v; time = Date.now(); ref = this.instances; results = []; for (k in ref) { v = ref[k]; try { if ((await v._store.__groupCheck__(time))) { results.push(this.deleteKey(k)); } else { results.push(void 0); } } catch (error) { e = error; results.push(v.Events.trigger("error", e)); } } return results; }, this.timeout / 2))).unref === "function" ? base.unref() : void 0; } updateSettings(options = {}) { parser$2.overwrite(options, this.defaults, this); parser$2.overwrite(options, options, this.limiterOptions); if (options.timeout != null) { return this._startAutoCleanup(); } } disconnect(flush = true) { var ref; if (!this.sharedConnection) { return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; } } } Group.prototype.defaults = { timeout: 1000 * 60 * 5, connection: null, Promise: Promise, id: "group-key" }; return Group; }).call(commonjsGlobal); var Group_1 = Group; var Batcher, Events$3, parser$3; parser$3 = parser; Events$3 = Events_1; Batcher = (function() { class Batcher { constructor(options = {}) { this.options = options; parser$3.load(this.options, this.defaults, this); this.Events = new Events$3(this); this._arr = []; this._resetPromise(); this._lastFlush = Date.now(); } _resetPromise() { return this._promise = new this.Promise((res, rej) => { return this._resolve = res; }); } _flush() { clearTimeout(this._timeout); this._lastFlush = Date.now(); this._resolve(); this.Events.trigger("batch", this._arr); this._arr = []; return this._resetPromise(); } add(data) { var ret; this._arr.push(data); ret = this._promise; if (this._arr.length === this.maxSize) { this._flush(); } else if ((this.maxTime != null) && this._arr.length === 1) { this._timeout = setTimeout(() => { return this._flush(); }, this.maxTime); } return ret; } } Batcher.prototype.defaults = { maxTime: null, maxSize: null, Promise: Promise }; return Batcher; }).call(commonjsGlobal); var Batcher_1 = Batcher; var require$$3$1 = () => console.log('You must import the full version of Bottleneck in order to use this feature.'); var require$$7 = getCjsExportFromNamespace(version$2); var Bottleneck, DEFAULT_PRIORITY, Events$4, LocalDatastore$1, NUM_PRIORITIES, Queues$1, RedisDatastore$1, States$1, Sync$1, parser$4, splice$1 = [].splice; NUM_PRIORITIES = 10; DEFAULT_PRIORITY = 5; parser$4 = parser; Queues$1 = Queues_1; LocalDatastore$1 = LocalDatastore_1; RedisDatastore$1 = require$$3$1; Events$4 = Events_1; States$1 = States_1; Sync$1 = Sync_1; Bottleneck = (function() { class Bottleneck { constructor(options = {}, ...invalid) { var storeInstanceOptions, storeOptions; this._drainOne = this._drainOne.bind(this); this.submit = this.submit.bind(this); this.schedule = this.schedule.bind(this); this.updateSettings = this.updateSettings.bind(this); this.incrementReservoir = this.incrementReservoir.bind(this); this._validateOptions(options, invalid); parser$4.load(options, this.instanceDefaults, this); this._queues = new Queues$1(NUM_PRIORITIES); this._scheduled = {}; this._states = new States$1(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); this._limiter = null; this.Events = new Events$4(this); this._submitLock = new Sync$1("submit", this.Promise); this._registerLock = new Sync$1("register", this.Promise); storeOptions = parser$4.load(options, this.storeDefaults, {}); this._store = (function() { if (this.datastore === "redis" || this.datastore === "ioredis" || (this.connection != null)) { storeInstanceOptions = parser$4.load(options, this.redisStoreDefaults, {}); return new RedisDatastore$1(this, storeOptions, storeInstanceOptions); } else if (this.datastore === "local") { storeInstanceOptions = parser$4.load(options, this.localStoreDefaults, {}); return new LocalDatastore$1(this, storeOptions, storeInstanceOptions); } else { throw new Bottleneck.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); } }).call(this); this._queues.on("leftzero", () => { var base; return typeof (base = this._store.heartbeat).ref === "function" ? base.ref() : void 0; }); this._queues.on("zero", () => { var base; return typeof (base = this._store.heartbeat).unref === "function" ? base.unref() : void 0; }); } _validateOptions(options, invalid) { if (!((options != null) && typeof options === "object" && invalid.length === 0)) { throw new Bottleneck.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); } } ready() { return this._store.ready; } clients() { return this._store.clients; } channel() { return `b_${this.id}`; } channel_client() { return `b_${this.id}_${this._store.clientId}`; } publish(message) { return this._store.__publish__(message); } disconnect(flush = true) { return this._store.__disconnect__(flush); } chain(_limiter) { this._limiter = _limiter; return this; } queued(priority) { return this._queues.queued(priority); } empty() { return this.queued() === 0 && this._submitLock.isEmpty(); } running() { return this._store.__running__(); } done() { return this._store.__done__(); } jobStatus(id) { return this._states.jobStatus(id); } jobs(status) { return this._states.statusJobs(status); } counts() { return this._states.statusCounts(); } _sanitizePriority(priority) { var sProperty; sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; if (sProperty < 0) { return 0; } else if (sProperty > NUM_PRIORITIES - 1) { return NUM_PRIORITIES - 1; } else { return sProperty; } } _randomIndex() { return Math.random().toString(36).slice(2); } check(weight = 1) { return this._store.__check__(weight); } _run(next, wait, index) { var completed, done; this.Events.trigger("debug", `Scheduling ${next.options.id}`, { args: next.args, options: next.options }); done = false; completed = async(...args) => { var e, running; if (!done) { try { done = true; this._states.next(next.options.id); // DONE clearTimeout(this._scheduled[index].expiration); delete this._scheduled[index]; this.Events.trigger("debug", `Completed ${next.options.id}`, { args: next.args, options: next.options }); this.Events.trigger("done", `Completed ${next.options.id}`, { args: next.args, options: next.options }); ({running} = (await this._store.__free__(index, next.options.weight))); this.Events.trigger("debug", `Freed ${next.options.id}`, { args: next.args, options: next.options }); if (running === 0 && this.empty()) { this.Events.trigger("idle"); } return typeof next.cb === "function" ? next.cb(...args) : void 0; } catch (error) { e = error; return this.Events.trigger("error", e); } } }; this._states.next(next.options.id); // RUNNING return this._scheduled[index] = { timeout: setTimeout(() => { this.Events.trigger("debug", `Executing ${next.options.id}`, { args: next.args, options: next.options }); this._states.next(next.options.id); // EXECUTING if (this._limiter != null) { return this._limiter.submit(next.options, next.task, ...next.args, completed); } else { return next.task(...next.args, completed); } }, wait), expiration: next.options.expiration != null ? setTimeout(() => { return completed(new Bottleneck.prototype.BottleneckError(`This job timed out after ${next.options.expiration} ms.`)); }, wait + next.options.expiration) : void 0, job: next }; } _drainOne(capacity) { return this._registerLock.schedule(() => { var args, index, next, options, queue; if (this.queued() === 0) { return this.Promise.resolve(false); } queue = this._queues.getFirst(); ({options, args} = next = queue.first()); if ((capacity != null) && options.weight > capacity) { return this.Promise.resolve(false); } this.Events.trigger("debug", `Draining ${options.id}`, {args, options}); index = this._randomIndex(); return this._store.__register__(index, options.weight, options.expiration).then(({success, wait, reservoir}) => { var empty; this.Events.trigger("debug", `Drained ${options.id}`, {success, args, options}); if (success) { queue.shift(); empty = this.empty(); if (empty) { this.Events.trigger("empty"); } if (reservoir === 0) { this.Events.trigger("depleted", empty); } this._run(next, wait, index); } return this.Promise.resolve(success); }); }); } _drainAll(capacity) { return this._drainOne(capacity).then((success) => { if (success) { return this._drainAll(); } else { return this.Promise.resolve(success); } }).catch((e) => { return this.Events.trigger("error", e); }); } _drop(job, message = "This job has been dropped by Bottleneck") { if (this._states.remove(job.options.id)) { if (this.rejectOnDrop) { if (typeof job.cb === "function") { job.cb(new Bottleneck.prototype.BottleneckError(message)); } } return this.Events.trigger("dropped", job); } } _dropAllQueued(message) { return this._queues.shiftAll((job) => { return this._drop(job, message); }); } stop(options = {}) { var done, waitForExecuting; options = parser$4.load(options, this.stopDefaults); waitForExecuting = (at) => { var finished; finished = () => { var counts; counts = this._states.counts; return (counts[0] + counts[1] + counts[2] + counts[3]) === at; }; return new this.Promise((resolve, reject) => { if (finished()) { return resolve(); } else { return this.on("done", () => { if (finished()) { this.removeAllListeners("done"); return resolve(); } }); } }); }; done = options.dropWaitingJobs ? (this._run = (next) => { return this._drop(next, options.dropErrorMessage); }, this._drainOne = () => { return this.Promise.resolve(false); }, this._registerLock.schedule(() => { return this._submitLock.schedule(() => { var k, ref, v; ref = this._scheduled; for (k in ref) { v = ref[k]; if (this.jobStatus(v.job.options.id) === "RUNNING") { clearTimeout(v.timeout); clearTimeout(v.expiration); this._drop(v.job, options.dropErrorMessage); } } this._dropAllQueued(options.dropErrorMessage); return waitForExecuting(0); }); })) : this.schedule({ priority: NUM_PRIORITIES - 1, weight: 0 }, () => { return waitForExecuting(1); }); this.submit = (...args) => { var cb, ref; ref = args, [...args] = ref, [cb] = splice$1.call(args, -1); return typeof cb === "function" ? cb(new Bottleneck.prototype.BottleneckError(options.enqueueErrorMessage)) : void 0; }; this.stop = () => { return this.Promise.reject(new Bottleneck.prototype.BottleneckError("stop() has already been called")); }; return done; } submit(...args) { var cb, job, options, ref, ref1, task; if (typeof args[0] === "function") { ref = args, [task, ...args] = ref, [cb] = splice$1.call(args, -1); options = parser$4.load({}, this.jobDefaults, {}); } else { ref1 = args, [options, task, ...args] = ref1, [cb] = splice$1.call(args, -1); options = parser$4.load(options, this.jobDefaults); } job = {options, task, args, cb}; options.priority = this._sanitizePriority(options.priority); if (options.id === this.jobDefaults.id) { options.id = `${options.id}-${this._randomIndex()}`; } if (this.jobStatus(options.id) != null) { if (typeof job.cb === "function") { job.cb(new Bottleneck.prototype.BottleneckError(`A job with the same id already exists (id=${options.id})`)); } return false; } this._states.start(options.id); // RECEIVED this.Events.trigger("debug", `Queueing ${options.id}`, {args, options}); return this._submitLock.schedule(async() => { var blocked, e, reachedHWM, shifted, strategy; try { ({reachedHWM, blocked, strategy} = (await this._store.__submit__(this.queued(), options.weight))); this.Events.trigger("debug", `Queued ${options.id}`, {args, options, reachedHWM, blocked}); } catch (error) { e = error; this._states.remove(options.id); this.Events.trigger("debug", `Could not queue ${options.id}`, { args, options, error: e }); if (typeof job.cb === "function") { job.cb(e); } return false; } if (blocked) { this._drop(job); return true; } else if (reachedHWM) { shifted = strategy === Bottleneck.prototype.strategy.LEAK ? this._queues.shiftLastFrom(options.priority) : strategy === Bottleneck.prototype.strategy.OVERFLOW_PRIORITY ? this._queues.shiftLastFrom(options.priority + 1) : strategy === Bottleneck.prototype.strategy.OVERFLOW ? job : void 0; if (shifted != null) { this._drop(shifted); } if ((shifted == null) || strategy === Bottleneck.prototype.strategy.OVERFLOW) { if (shifted == null) { this._drop(job); } return reachedHWM; } } this._states.next(job.options.id); // QUEUED this._queues.push(options.priority, job); await this._drainAll(); return reachedHWM; }); } schedule(...args) { var options, task, wrapped; if (typeof args[0] === "function") { [task, ...args] = args; options = parser$4.load({}, this.jobDefaults, {}); } else { [options, task, ...args] = args; options = parser$4.load(options, this.jobDefaults); } wrapped = (...args) => { var cb, ref, returned; ref = args, [...args] = ref, [cb] = splice$1.call(args, -1); returned = task(...args); return (!(((returned != null ? returned.then : void 0) != null) && typeof returned.then === "function") ? this.Promise.resolve(returned) : returned).then(function(...args) { return cb(null, ...args); }).catch(function(...args) { return cb(...args); }); }; return new this.Promise((resolve, reject) => { return this.submit(options, wrapped, ...args, function(...args) { return (args[0] != null ? reject : (args.shift(), resolve))(...args); }).catch((e) => { return this.Events.trigger("error", e); }); }); } wrap(fn) { var wrapped; wrapped = (...args) => { return this.schedule(fn, ...args); }; wrapped.withOptions = (options, ...args) => { return this.schedule(options, fn, ...args); }; return wrapped; } async updateSettings(options = {}) { await this._store.__updateSettings__(parser$4.overwrite(options, this.storeDefaults)); parser$4.overwrite(options, this.instanceDefaults, this); return this; } currentReservoir() { return this._store.__currentReservoir__(); } incrementReservoir(incr = 0) { return this._store.__incrementReservoir__(incr); } } Bottleneck.default = Bottleneck; Bottleneck.Events = Events$4; Bottleneck.version = Bottleneck.prototype.version = require$$7.version; Bottleneck.strategy = Bottleneck.prototype.strategy = { LEAK: 1, OVERFLOW: 2, OVERFLOW_PRIORITY: 4, BLOCK: 3 }; Bottleneck.BottleneckError = Bottleneck.prototype.BottleneckError = BottleneckError_1; Bottleneck.Group = Bottleneck.prototype.Group = Group_1; Bottleneck.RedisConnection = Bottleneck.prototype.RedisConnection = require$$2; Bottleneck.IORedisConnection = Bottleneck.prototype.IORedisConnection = require$$3; Bottleneck.Batcher = Bottleneck.prototype.Batcher = Batcher_1; Bottleneck.prototype.jobDefaults = { priority: DEFAULT_PRIORITY, weight: 1, expiration: null, id: "<no-id>" }; Bottleneck.prototype.storeDefaults = { maxConcurrent: null, minTime: 0, highWater: null, strategy: Bottleneck.prototype.strategy.LEAK, penalty: null, reservoir: null, reservoirRefreshInterval: null, reservoirRefreshAmount: null }; Bottleneck.prototype.localStoreDefaults = { Promise: Promise, timeout: null, heartbeatInterval: 250 }; Bottleneck.prototype.redisStoreDefaults = { Promise: Promise, timeout: null, heartbeatInterval: 5000, clientOptions: {}, clusterNodes: null, clearDatastore: false, connection: null }; Bottleneck.prototype.instanceDefaults = { datastore: "local", connection: null, id: "<no-id>", rejectOnDrop: true, trackDoneStatus: false, Promise: Promise }; Bottleneck.prototype.stopDefaults = { enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", dropWaitingJobs: true, dropErrorMessage: "This limiter has been stopped." }; return Bottleneck; }).call(commonjsGlobal); var Bottleneck_1 = Bottleneck; var lib = Bottleneck_1; return lib; })));