UNPKG

39.6 kBJavaScriptView Raw
1/**
2 * This file contains the Bottleneck library (MIT), compiled to ES2017, and without Clustering support.
3 * https://github.com/SGrondin/bottleneck
4 */
5(function (global, factory) {
6 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
7 typeof define === 'function' && define.amd ? define(factory) :
8 (global.Bottleneck = factory());
9}(this, (function () { 'use strict';
10
11 var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
12
13 function getCjsExportFromNamespace (n) {
14 return n && n.default || n;
15 }
16
17 var load = function(received, defaults, onto = {}) {
18 var k, ref, v;
19 for (k in defaults) {
20 v = defaults[k];
21 onto[k] = (ref = received[k]) != null ? ref : v;
22 }
23 return onto;
24 };
25
26 var overwrite = function(received, defaults, onto = {}) {
27 var k, v;
28 for (k in received) {
29 v = received[k];
30 if (defaults[k] !== void 0) {
31 onto[k] = v;
32 }
33 }
34 return onto;
35 };
36
37 var parser = {
38 load: load,
39 overwrite: overwrite
40 };
41
42 var DLList;
43
44 DLList = class DLList {
45 constructor(_queues) {
46 this._queues = _queues;
47 this._first = null;
48 this._last = null;
49 this.length = 0;
50 }
51
52 push(value) {
53 var node, ref1;
54 this.length++;
55 if ((ref1 = this._queues) != null) {
56 ref1.incr();
57 }
58 node = {
59 value,
60 next: null
61 };
62 if (this._last != null) {
63 this._last.next = node;
64 this._last = node;
65 } else {
66 this._first = this._last = node;
67 }
68 return void 0;
69 }
70
71 shift() {
72 var ref1, ref2, value;
73 if (this._first == null) {
74 return void 0;
75 } else {
76 this.length--;
77 if ((ref1 = this._queues) != null) {
78 ref1.decr();
79 }
80 }
81 value = this._first.value;
82 this._first = (ref2 = this._first.next) != null ? ref2 : (this._last = null);
83 return value;
84 }
85
86 first() {
87 if (this._first != null) {
88 return this._first.value;
89 }
90 }
91
92 getArray() {
93 var node, ref, results;
94 node = this._first;
95 results = [];
96 while (node != null) {
97 results.push((ref = node, node = node.next, ref.value));
98 }
99 return results;
100 }
101
102 forEachShift(cb) {
103 var node;
104 node = this.shift();
105 while (node != null) {
106 (cb(node), node = this.shift());
107 }
108 return void 0;
109 }
110
111 };
112
113 var DLList_1 = DLList;
114
115 var Events;
116
117 Events = class Events {
118 constructor(instance) {
119 this.instance = instance;
120 this._events = {};
121 if ((this.instance.on != null) || (this.instance.once != null) || (this.instance.removeAllListeners != null)) {
122 throw new Error("An Emitter already exists for this object");
123 }
124 this.instance.on = (name, cb) => {
125 return this._addListener(name, "many", cb);
126 };
127 this.instance.once = (name, cb) => {
128 return this._addListener(name, "once", cb);
129 };
130 this.instance.removeAllListeners = (name = null) => {
131 if (name != null) {
132 return delete this._events[name];
133 } else {
134 return this._events = {};
135 }
136 };
137 }
138
139 _addListener(name, status, cb) {
140 var base;
141 if ((base = this._events)[name] == null) {
142 base[name] = [];
143 }
144 this._events[name].push({cb, status});
145 return this.instance;
146 }
147
148 listenerCount(name) {
149 if (this._events[name] != null) {
150 return this._events[name].length;
151 } else {
152 return 0;
153 }
154 }
155
156 async trigger(name, ...args) {
157 var e, promises;
158 try {
159 if (name !== "debug") {
160 this.trigger("debug", `Event triggered: ${name}`, args);
161 }
162 if (this._events[name] == null) {
163 return;
164 }
165 this._events[name] = this._events[name].filter(function(listener) {
166 return listener.status !== "none";
167 });
168 promises = this._events[name].map(async(listener) => {
169 var e, returned;
170 if (listener.status === "none") {
171 return;
172 }
173 if (listener.status === "once") {
174 listener.status = "none";
175 }
176 try {
177 returned = typeof listener.cb === "function" ? listener.cb(...args) : void 0;
178 if (typeof (returned != null ? returned.then : void 0) === "function") {
179 return (await returned);
180 } else {
181 return returned;
182 }
183 } catch (error) {
184 e = error;
185 {
186 this.trigger("error", e);
187 }
188 return null;
189 }
190 });
191 return ((await Promise.all(promises))).find(function(x) {
192 return x != null;
193 });
194 } catch (error) {
195 e = error;
196 {
197 this.trigger("error", e);
198 }
199 return null;
200 }
201 }
202
203 };
204
205 var Events_1 = Events;
206
207 var DLList$1, Events$1, Queues;
208
209 DLList$1 = DLList_1;
210
211 Events$1 = Events_1;
212
213 Queues = class Queues {
214 constructor(num_priorities) {
215 var i;
216 this.Events = new Events$1(this);
217 this._length = 0;
218 this._lists = (function() {
219 var j, ref, results;
220 results = [];
221 for (i = j = 1, ref = num_priorities; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
222 results.push(new DLList$1(this));
223 }
224 return results;
225 }).call(this);
226 }
227
228 incr() {
229 if (this._length++ === 0) {
230 return this.Events.trigger("leftzero");
231 }
232 }
233
234 decr() {
235 if (--this._length === 0) {
236 return this.Events.trigger("zero");
237 }
238 }
239
240 push(priority, job) {
241 return this._lists[priority].push(job);
242 }
243
244 queued(priority) {
245 if (priority != null) {
246 return this._lists[priority].length;
247 } else {
248 return this._length;
249 }
250 }
251
252 shiftAll(fn) {
253 return this._lists.forEach(function(list) {
254 return list.forEachShift(fn);
255 });
256 }
257
258 getFirst(arr = this._lists) {
259 var j, len, list;
260 for (j = 0, len = arr.length; j < len; j++) {
261 list = arr[j];
262 if (list.length > 0) {
263 return list;
264 }
265 }
266 return [];
267 }
268
269 shiftLastFrom(priority) {
270 return this.getFirst(this._lists.slice(priority).reverse()).shift();
271 }
272
273 };
274
275 var Queues_1 = Queues;
276
277 var BottleneckError;
278
279 BottleneckError = class BottleneckError extends Error {};
280
281 var BottleneckError_1 = BottleneckError;
282
283 var BottleneckError$1, LocalDatastore, parser$1;
284
285 parser$1 = parser;
286
287 BottleneckError$1 = BottleneckError_1;
288
289 LocalDatastore = class LocalDatastore {
290 constructor(instance, storeOptions, storeInstanceOptions) {
291 this.instance = instance;
292 this.storeOptions = storeOptions;
293 this.clientId = this.instance._randomIndex();
294 parser$1.load(storeInstanceOptions, storeInstanceOptions, this);
295 this._nextRequest = this._lastReservoirRefresh = Date.now();
296 this._running = 0;
297 this._done = 0;
298 this._unblockTime = 0;
299 this.ready = this.Promise.resolve();
300 this.clients = {};
301 this._startHeartbeat();
302 }
303
304 _startHeartbeat() {
305 var base;
306 if ((this.heartbeat == null) && (this.storeOptions.reservoirRefreshInterval != null) && (this.storeOptions.reservoirRefreshAmount != null)) {
307 return typeof (base = (this.heartbeat = setInterval(() => {
308 var now;
309 now = Date.now();
310 if (now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) {
311 this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount;
312 this._lastReservoirRefresh = now;
313 return this.instance._drainAll(this.computeCapacity());
314 }
315 }, this.heartbeatInterval))).unref === "function" ? base.unref() : void 0;
316 } else {
317 return clearInterval(this.heartbeat);
318 }
319 }
320
321 async __publish__(message) {
322 await this.yieldLoop();
323 return this.instance.Events.trigger("message", message.toString());
324 }
325
326 async __disconnect__(flush) {
327 await this.yieldLoop();
328 clearInterval(this.heartbeat);
329 return this.Promise.resolve();
330 }
331
332 yieldLoop(t = 0) {
333 return new this.Promise(function(resolve, reject) {
334 return setTimeout(resolve, t);
335 });
336 }
337
338 computePenalty() {
339 var ref;
340 return (ref = this.storeOptions.penalty) != null ? ref : (15 * this.storeOptions.minTime) || 5000;
341 }
342
343 async __updateSettings__(options) {
344 await this.yieldLoop();
345 parser$1.overwrite(options, options, this.storeOptions);
346 this._startHeartbeat();
347 this.instance._drainAll(this.computeCapacity());
348 return true;
349 }
350
351 async __running__() {
352 await this.yieldLoop();
353 return this._running;
354 }
355
356 async __queued__() {
357 await this.yieldLoop();
358 return this.instance.queued();
359 }
360
361 async __done__() {
362 await this.yieldLoop();
363 return this._done;
364 }
365
366 async __groupCheck__(time) {
367 await this.yieldLoop();
368 return (this._nextRequest + this.timeout) < time;
369 }
370
371 computeCapacity() {
372 var maxConcurrent, reservoir;
373 ({maxConcurrent, reservoir} = this.storeOptions);
374 if ((maxConcurrent != null) && (reservoir != null)) {
375 return Math.min(maxConcurrent - this._running, reservoir);
376 } else if (maxConcurrent != null) {
377 return maxConcurrent - this._running;
378 } else if (reservoir != null) {
379 return reservoir;
380 } else {
381 return null;
382 }
383 }
384
385 conditionsCheck(weight) {
386 var capacity;
387 capacity = this.computeCapacity();
388 return (capacity == null) || weight <= capacity;
389 }
390
391 async __incrementReservoir__(incr) {
392 var reservoir;
393 await this.yieldLoop();
394 reservoir = this.storeOptions.reservoir += incr;
395 this.instance._drainAll(this.computeCapacity());
396 return reservoir;
397 }
398
399 async __currentReservoir__() {
400 await this.yieldLoop();
401 return this.storeOptions.reservoir;
402 }
403
404 isBlocked(now) {
405 return this._unblockTime >= now;
406 }
407
408 check(weight, now) {
409 return this.conditionsCheck(weight) && (this._nextRequest - now) <= 0;
410 }
411
412 async __check__(weight) {
413 var now;
414 await this.yieldLoop();
415 now = Date.now();
416 return this.check(weight, now);
417 }
418
419 async __register__(index, weight, expiration) {
420 var now, wait;
421 await this.yieldLoop();
422 now = Date.now();
423 if (this.conditionsCheck(weight)) {
424 this._running += weight;
425 if (this.storeOptions.reservoir != null) {
426 this.storeOptions.reservoir -= weight;
427 }
428 wait = Math.max(this._nextRequest - now, 0);
429 this._nextRequest = now + wait + this.storeOptions.minTime;
430 return {
431 success: true,
432 wait,
433 reservoir: this.storeOptions.reservoir
434 };
435 } else {
436 return {
437 success: false
438 };
439 }
440 }
441
442 strategyIsBlock() {
443 return this.storeOptions.strategy === 3;
444 }
445
446 async __submit__(queueLength, weight) {
447 var blocked, now, reachedHWM;
448 await this.yieldLoop();
449 if ((this.storeOptions.maxConcurrent != null) && weight > this.storeOptions.maxConcurrent) {
450 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}`);
451 }
452 now = Date.now();
453 reachedHWM = (this.storeOptions.highWater != null) && queueLength === this.storeOptions.highWater && !this.check(weight, now);
454 blocked = this.strategyIsBlock() && (reachedHWM || this.isBlocked(now));
455 if (blocked) {
456 this._unblockTime = now + this.computePenalty();
457 this._nextRequest = this._unblockTime + this.storeOptions.minTime;
458 this.instance._dropAllQueued();
459 }
460 return {
461 reachedHWM,
462 blocked,
463 strategy: this.storeOptions.strategy
464 };
465 }
466
467 async __free__(index, weight) {
468 await this.yieldLoop();
469 this._running -= weight;
470 this._done += weight;
471 this.instance._drainAll(this.computeCapacity());
472 return {
473 running: this._running
474 };
475 }
476
477 };
478
479 var LocalDatastore_1 = LocalDatastore;
480
481 var BottleneckError$2, States;
482
483 BottleneckError$2 = BottleneckError_1;
484
485 States = class States {
486 constructor(status1) {
487 this.status = status1;
488 this.jobs = {};
489 this.counts = this.status.map(function() {
490 return 0;
491 });
492 }
493
494 next(id) {
495 var current, next;
496 current = this.jobs[id];
497 next = current + 1;
498 if ((current != null) && next < this.status.length) {
499 this.counts[current]--;
500 this.counts[next]++;
501 return this.jobs[id]++;
502 } else if (current != null) {
503 this.counts[current]--;
504 return delete this.jobs[id];
505 }
506 }
507
508 start(id) {
509 var initial;
510 initial = 0;
511 this.jobs[id] = initial;
512 return this.counts[initial]++;
513 }
514
515 remove(id) {
516 var current;
517 current = this.jobs[id];
518 if (current != null) {
519 this.counts[current]--;
520 delete this.jobs[id];
521 }
522 return current != null;
523 }
524
525 jobStatus(id) {
526 var ref;
527 return (ref = this.status[this.jobs[id]]) != null ? ref : null;
528 }
529
530 statusJobs(status) {
531 var k, pos, ref, results, v;
532 if (status != null) {
533 pos = this.status.indexOf(status);
534 if (pos < 0) {
535 throw new BottleneckError$2(`status must be one of ${this.status.join(', ')}`);
536 }
537 ref = this.jobs;
538 results = [];
539 for (k in ref) {
540 v = ref[k];
541 if (v === pos) {
542 results.push(k);
543 }
544 }
545 return results;
546 } else {
547 return Object.keys(this.jobs);
548 }
549 }
550
551 statusCounts() {
552 return this.counts.reduce(((acc, v, i) => {
553 acc[this.status[i]] = v;
554 return acc;
555 }), {});
556 }
557
558 };
559
560 var States_1 = States;
561
562 var DLList$2, Sync,
563 splice = [].splice;
564
565 DLList$2 = DLList_1;
566
567 Sync = class Sync {
568 constructor(name, Promise) {
569 this.submit = this.submit.bind(this);
570 this.name = name;
571 this.Promise = Promise;
572 this._running = 0;
573 this._queue = new DLList$2();
574 }
575
576 isEmpty() {
577 return this._queue.length === 0;
578 }
579
580 _tryToRun() {
581 var next;
582 if ((this._running < 1) && this._queue.length > 0) {
583 this._running++;
584 next = this._queue.shift();
585 return next.task(...next.args, (...args) => {
586 this._running--;
587 this._tryToRun();
588 return typeof next.cb === "function" ? next.cb(...args) : void 0;
589 });
590 }
591 }
592
593 submit(task, ...args) {
594 var cb, ref;
595 ref = args, [...args] = ref, [cb] = splice.call(args, -1);
596 this._queue.push({task, args, cb});
597 return this._tryToRun();
598 }
599
600 schedule(task, ...args) {
601 var wrapped;
602 wrapped = function(...args) {
603 var cb, ref;
604 ref = args, [...args] = ref, [cb] = splice.call(args, -1);
605 return (task(...args)).then(function(...args) {
606 return cb(null, ...args);
607 }).catch(function(...args) {
608 return cb(...args);
609 });
610 };
611 return new this.Promise((resolve, reject) => {
612 return this.submit(wrapped, ...args, function(...args) {
613 return (args[0] != null ? reject : (args.shift(), resolve))(...args);
614 });
615 });
616 }
617
618 };
619
620 var Sync_1 = Sync;
621
622 var version = "2.16.0";
623 var version$1 = {
624 version: version
625 };
626
627 var version$2 = /*#__PURE__*/Object.freeze({
628 version: version,
629 default: version$1
630 });
631
632 var require$$2 = () => console.log('You must import the full version of Bottleneck in order to use this feature.');
633
634 var require$$3 = () => console.log('You must import the full version of Bottleneck in order to use this feature.');
635
636 var require$$4 = () => console.log('You must import the full version of Bottleneck in order to use this feature.');
637
638 var Events$2, Group, IORedisConnection$1, RedisConnection$1, Scripts$1, parser$2;
639
640 parser$2 = parser;
641
642 Events$2 = Events_1;
643
644 RedisConnection$1 = require$$2;
645
646 IORedisConnection$1 = require$$3;
647
648 Scripts$1 = require$$4;
649
650 Group = (function() {
651 class Group {
652 constructor(limiterOptions = {}) {
653 this.deleteKey = this.deleteKey.bind(this);
654 this.updateSettings = this.updateSettings.bind(this);
655 this.limiterOptions = limiterOptions;
656 parser$2.load(this.limiterOptions, this.defaults, this);
657 this.Events = new Events$2(this);
658 this.instances = {};
659 this.Bottleneck = Bottleneck_1;
660 this._startAutoCleanup();
661 this.sharedConnection = this.connection != null;
662 if (this.connection == null) {
663 if (this.limiterOptions.datastore === "redis") {
664 this.connection = new RedisConnection$1(Object.assign({}, this.limiterOptions, {Events: this.Events}));
665 } else if (this.limiterOptions.datastore === "ioredis") {
666 this.connection = new IORedisConnection$1(Object.assign({}, this.limiterOptions, {Events: this.Events}));
667 }
668 }
669 }
670
671 key(key = "") {
672 var ref;
673 return (ref = this.instances[key]) != null ? ref : (() => {
674 var limiter;
675 limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, {
676 id: `${this.id}-${key}`,
677 timeout: this.timeout,
678 connection: this.connection
679 }));
680 this.Events.trigger("created", limiter, key);
681 return limiter;
682 })();
683 }
684
685 async deleteKey(key = "") {
686 var deleted, instance;
687 instance = this.instances[key];
688 if (this.connection) {
689 deleted = (await this.connection.__runCommand__(['del', ...Scripts$1.allKeys(`${this.id}-${key}`)]));
690 }
691 if (instance != null) {
692 delete this.instances[key];
693 await instance.disconnect();
694 }
695 return (instance != null) || deleted > 0;
696 }
697
698 limiters() {
699 var k, ref, results, v;
700 ref = this.instances;
701 results = [];
702 for (k in ref) {
703 v = ref[k];
704 results.push({
705 key: k,
706 limiter: v
707 });
708 }
709 return results;
710 }
711
712 keys() {
713 return Object.keys(this.instances);
714 }
715
716 async clusterKeys() {
717 var cursor, end, found, i, k, keys, len, next, start;
718 if (this.connection == null) {
719 return this.Promise.resolve(this.keys());
720 }
721 keys = [];
722 cursor = null;
723 start = `b_${this.id}-`.length;
724 end = "_settings".length;
725 while (cursor !== 0) {
726 [next, found] = (await this.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${this.id}-*_settings`, "count", 10000]));
727 cursor = ~~next;
728 for (i = 0, len = found.length; i < len; i++) {
729 k = found[i];
730 keys.push(k.slice(start, -end));
731 }
732 }
733 return keys;
734 }
735
736 _startAutoCleanup() {
737 var base;
738 clearInterval(this.interval);
739 return typeof (base = (this.interval = setInterval(async() => {
740 var e, k, ref, results, time, v;
741 time = Date.now();
742 ref = this.instances;
743 results = [];
744 for (k in ref) {
745 v = ref[k];
746 try {
747 if ((await v._store.__groupCheck__(time))) {
748 results.push(this.deleteKey(k));
749 } else {
750 results.push(void 0);
751 }
752 } catch (error) {
753 e = error;
754 results.push(v.Events.trigger("error", e));
755 }
756 }
757 return results;
758 }, this.timeout / 2))).unref === "function" ? base.unref() : void 0;
759 }
760
761 updateSettings(options = {}) {
762 parser$2.overwrite(options, this.defaults, this);
763 parser$2.overwrite(options, options, this.limiterOptions);
764 if (options.timeout != null) {
765 return this._startAutoCleanup();
766 }
767 }
768
769 disconnect(flush = true) {
770 var ref;
771 if (!this.sharedConnection) {
772 return (ref = this.connection) != null ? ref.disconnect(flush) : void 0;
773 }
774 }
775
776 }
777 Group.prototype.defaults = {
778 timeout: 1000 * 60 * 5,
779 connection: null,
780 Promise: Promise,
781 id: "group-key"
782 };
783
784 return Group;
785
786 }).call(commonjsGlobal);
787
788 var Group_1 = Group;
789
790 var Batcher, Events$3, parser$3;
791
792 parser$3 = parser;
793
794 Events$3 = Events_1;
795
796 Batcher = (function() {
797 class Batcher {
798 constructor(options = {}) {
799 this.options = options;
800 parser$3.load(this.options, this.defaults, this);
801 this.Events = new Events$3(this);
802 this._arr = [];
803 this._resetPromise();
804 this._lastFlush = Date.now();
805 }
806
807 _resetPromise() {
808 return this._promise = new this.Promise((res, rej) => {
809 return this._resolve = res;
810 });
811 }
812
813 _flush() {
814 clearTimeout(this._timeout);
815 this._lastFlush = Date.now();
816 this._resolve();
817 this.Events.trigger("batch", this._arr);
818 this._arr = [];
819 return this._resetPromise();
820 }
821
822 add(data) {
823 var ret;
824 this._arr.push(data);
825 ret = this._promise;
826 if (this._arr.length === this.maxSize) {
827 this._flush();
828 } else if ((this.maxTime != null) && this._arr.length === 1) {
829 this._timeout = setTimeout(() => {
830 return this._flush();
831 }, this.maxTime);
832 }
833 return ret;
834 }
835
836 }
837 Batcher.prototype.defaults = {
838 maxTime: null,
839 maxSize: null,
840 Promise: Promise
841 };
842
843 return Batcher;
844
845 }).call(commonjsGlobal);
846
847 var Batcher_1 = Batcher;
848
849 var require$$3$1 = () => console.log('You must import the full version of Bottleneck in order to use this feature.');
850
851 var require$$7 = getCjsExportFromNamespace(version$2);
852
853 var Bottleneck, DEFAULT_PRIORITY, Events$4, LocalDatastore$1, NUM_PRIORITIES, Queues$1, RedisDatastore$1, States$1, Sync$1, parser$4,
854 splice$1 = [].splice;
855
856 NUM_PRIORITIES = 10;
857
858 DEFAULT_PRIORITY = 5;
859
860 parser$4 = parser;
861
862 Queues$1 = Queues_1;
863
864 LocalDatastore$1 = LocalDatastore_1;
865
866 RedisDatastore$1 = require$$3$1;
867
868 Events$4 = Events_1;
869
870 States$1 = States_1;
871
872 Sync$1 = Sync_1;
873
874 Bottleneck = (function() {
875 class Bottleneck {
876 constructor(options = {}, ...invalid) {
877 var storeInstanceOptions, storeOptions;
878 this._drainOne = this._drainOne.bind(this);
879 this.submit = this.submit.bind(this);
880 this.schedule = this.schedule.bind(this);
881 this.updateSettings = this.updateSettings.bind(this);
882 this.incrementReservoir = this.incrementReservoir.bind(this);
883 this._validateOptions(options, invalid);
884 parser$4.load(options, this.instanceDefaults, this);
885 this._queues = new Queues$1(NUM_PRIORITIES);
886 this._scheduled = {};
887 this._states = new States$1(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : []));
888 this._limiter = null;
889 this.Events = new Events$4(this);
890 this._submitLock = new Sync$1("submit", this.Promise);
891 this._registerLock = new Sync$1("register", this.Promise);
892 storeOptions = parser$4.load(options, this.storeDefaults, {});
893 this._store = (function() {
894 if (this.datastore === "redis" || this.datastore === "ioredis" || (this.connection != null)) {
895 storeInstanceOptions = parser$4.load(options, this.redisStoreDefaults, {});
896 return new RedisDatastore$1(this, storeOptions, storeInstanceOptions);
897 } else if (this.datastore === "local") {
898 storeInstanceOptions = parser$4.load(options, this.localStoreDefaults, {});
899 return new LocalDatastore$1(this, storeOptions, storeInstanceOptions);
900 } else {
901 throw new Bottleneck.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`);
902 }
903 }).call(this);
904 this._queues.on("leftzero", () => {
905 var base;
906 return typeof (base = this._store.heartbeat).ref === "function" ? base.ref() : void 0;
907 });
908 this._queues.on("zero", () => {
909 var base;
910 return typeof (base = this._store.heartbeat).unref === "function" ? base.unref() : void 0;
911 });
912 }
913
914 _validateOptions(options, invalid) {
915 if (!((options != null) && typeof options === "object" && invalid.length === 0)) {
916 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.");
917 }
918 }
919
920 ready() {
921 return this._store.ready;
922 }
923
924 clients() {
925 return this._store.clients;
926 }
927
928 channel() {
929 return `b_${this.id}`;
930 }
931
932 channel_client() {
933 return `b_${this.id}_${this._store.clientId}`;
934 }
935
936 publish(message) {
937 return this._store.__publish__(message);
938 }
939
940 disconnect(flush = true) {
941 return this._store.__disconnect__(flush);
942 }
943
944 chain(_limiter) {
945 this._limiter = _limiter;
946 return this;
947 }
948
949 queued(priority) {
950 return this._queues.queued(priority);
951 }
952
953 clusterQueued() {
954 return this._store.__queued__();
955 }
956
957 empty() {
958 return this.queued() === 0 && this._submitLock.isEmpty();
959 }
960
961 running() {
962 return this._store.__running__();
963 }
964
965 done() {
966 return this._store.__done__();
967 }
968
969 jobStatus(id) {
970 return this._states.jobStatus(id);
971 }
972
973 jobs(status) {
974 return this._states.statusJobs(status);
975 }
976
977 counts() {
978 return this._states.statusCounts();
979 }
980
981 _sanitizePriority(priority) {
982 var sProperty;
983 sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority;
984 if (sProperty < 0) {
985 return 0;
986 } else if (sProperty > NUM_PRIORITIES - 1) {
987 return NUM_PRIORITIES - 1;
988 } else {
989 return sProperty;
990 }
991 }
992
993 _randomIndex() {
994 return Math.random().toString(36).slice(2);
995 }
996
997 check(weight = 1) {
998 return this._store.__check__(weight);
999 }
1000
1001 _run(next, wait, index, retryCount) {
1002 var completed, done;
1003 this.Events.trigger("debug", `Scheduling ${next.options.id}`, {
1004 args: next.args,
1005 options: next.options
1006 });
1007 done = false;
1008 completed = async(...args) => {
1009 var e, error, eventInfo, retry, retryAfter, running;
1010 if (!done) {
1011 try {
1012 done = true;
1013 clearTimeout(this._scheduled[index].expiration);
1014 delete this._scheduled[index];
1015 eventInfo = {
1016 args: next.args,
1017 options: next.options,
1018 retryCount
1019 };
1020 if ((error = args[0]) != null) {
1021 retry = (await this.Events.trigger("failed", error, eventInfo));
1022 if (retry != null) {
1023 retryAfter = ~~retry;
1024 this.Events.trigger("retry", `Retrying ${next.options.id} after ${retryAfter} ms`, eventInfo);
1025 return this._run(next, retryAfter, index, retryCount + 1);
1026 }
1027 }
1028 this._states.next(next.options.id); // DONE
1029 this.Events.trigger("debug", `Completed ${next.options.id}`, eventInfo);
1030 this.Events.trigger("done", `Completed ${next.options.id}`, eventInfo);
1031 ({running} = (await this._store.__free__(index, next.options.weight)));
1032 this.Events.trigger("debug", `Freed ${next.options.id}`, eventInfo);
1033 if (running === 0 && this.empty()) {
1034 this.Events.trigger("idle");
1035 }
1036 return typeof next.cb === "function" ? next.cb(...args) : void 0;
1037 } catch (error1) {
1038 e = error1;
1039 return this.Events.trigger("error", e);
1040 }
1041 }
1042 };
1043 if (retryCount === 0) { // RUNNING
1044 this._states.next(next.options.id);
1045 }
1046 return this._scheduled[index] = {
1047 timeout: setTimeout(() => {
1048 this.Events.trigger("debug", `Executing ${next.options.id}`, {
1049 args: next.args,
1050 options: next.options
1051 });
1052 if (retryCount === 0) { // EXECUTING
1053 this._states.next(next.options.id);
1054 }
1055 if (this._limiter != null) {
1056 return this._limiter.submit(next.options, next.task, ...next.args, completed);
1057 } else {
1058 return next.task(...next.args, completed);
1059 }
1060 }, wait),
1061 expiration: next.options.expiration != null ? setTimeout(() => {
1062 return completed(new Bottleneck.prototype.BottleneckError(`This job timed out after ${next.options.expiration} ms.`));
1063 }, wait + next.options.expiration) : void 0,
1064 job: next
1065 };
1066 }
1067
1068 _drainOne(capacity) {
1069 return this._registerLock.schedule(() => {
1070 var args, index, next, options, queue;
1071 if (this.queued() === 0) {
1072 return this.Promise.resolve(null);
1073 }
1074 queue = this._queues.getFirst();
1075 ({options, args} = next = queue.first());
1076 if ((capacity != null) && options.weight > capacity) {
1077 return this.Promise.resolve(null);
1078 }
1079 this.Events.trigger("debug", `Draining ${options.id}`, {args, options});
1080 index = this._randomIndex();
1081 return this._store.__register__(index, options.weight, options.expiration).then(({success, wait, reservoir}) => {
1082 var empty;
1083 this.Events.trigger("debug", `Drained ${options.id}`, {success, args, options});
1084 if (success) {
1085 queue.shift();
1086 empty = this.empty();
1087 if (empty) {
1088 this.Events.trigger("empty");
1089 }
1090 if (reservoir === 0) {
1091 this.Events.trigger("depleted", empty);
1092 }
1093 this._run(next, wait, index, 0);
1094 return this.Promise.resolve(options.weight);
1095 } else {
1096 return this.Promise.resolve(null);
1097 }
1098 });
1099 });
1100 }
1101
1102 _drainAll(capacity, total = 0) {
1103 return this._drainOne(capacity).then((drained) => {
1104 var newCapacity;
1105 if (drained != null) {
1106 newCapacity = capacity != null ? capacity - drained : capacity;
1107 return this._drainAll(newCapacity, total + drained);
1108 } else {
1109 return this.Promise.resolve(total);
1110 }
1111 }).catch((e) => {
1112 return this.Events.trigger("error", e);
1113 });
1114 }
1115
1116 _drop(job, message = "This job has been dropped by Bottleneck") {
1117 if (this._states.remove(job.options.id)) {
1118 if (this.rejectOnDrop) {
1119 if (typeof job.cb === "function") {
1120 job.cb(new Bottleneck.prototype.BottleneckError(message));
1121 }
1122 }
1123 return this.Events.trigger("dropped", job);
1124 }
1125 }
1126
1127 _dropAllQueued(message) {
1128 return this._queues.shiftAll((job) => {
1129 return this._drop(job, message);
1130 });
1131 }
1132
1133 stop(options = {}) {
1134 var done, waitForExecuting;
1135 options = parser$4.load(options, this.stopDefaults);
1136 waitForExecuting = (at) => {
1137 var finished;
1138 finished = () => {
1139 var counts;
1140 counts = this._states.counts;
1141 return (counts[0] + counts[1] + counts[2] + counts[3]) === at;
1142 };
1143 return new this.Promise((resolve, reject) => {
1144 if (finished()) {
1145 return resolve();
1146 } else {
1147 return this.on("done", () => {
1148 if (finished()) {
1149 this.removeAllListeners("done");
1150 return resolve();
1151 }
1152 });
1153 }
1154 });
1155 };
1156 done = options.dropWaitingJobs ? (this._run = (next) => {
1157 return this._drop(next, options.dropErrorMessage);
1158 }, this._drainOne = () => {
1159 return this.Promise.resolve(null);
1160 }, this._registerLock.schedule(() => {
1161 return this._submitLock.schedule(() => {
1162 var k, ref, v;
1163 ref = this._scheduled;
1164 for (k in ref) {
1165 v = ref[k];
1166 if (this.jobStatus(v.job.options.id) === "RUNNING") {
1167 clearTimeout(v.timeout);
1168 clearTimeout(v.expiration);
1169 this._drop(v.job, options.dropErrorMessage);
1170 }
1171 }
1172 this._dropAllQueued(options.dropErrorMessage);
1173 return waitForExecuting(0);
1174 });
1175 })) : this.schedule({
1176 priority: NUM_PRIORITIES - 1,
1177 weight: 0
1178 }, () => {
1179 return waitForExecuting(1);
1180 });
1181 this.submit = (...args) => {
1182 var cb, ref;
1183 ref = args, [...args] = ref, [cb] = splice$1.call(args, -1);
1184 return typeof cb === "function" ? cb(new Bottleneck.prototype.BottleneckError(options.enqueueErrorMessage)) : void 0;
1185 };
1186 this.stop = () => {
1187 return this.Promise.reject(new Bottleneck.prototype.BottleneckError("stop() has already been called"));
1188 };
1189 return done;
1190 }
1191
1192 submit(...args) {
1193 var cb, job, options, ref, ref1, task;
1194 if (typeof args[0] === "function") {
1195 ref = args, [task, ...args] = ref, [cb] = splice$1.call(args, -1);
1196 options = parser$4.load({}, this.jobDefaults, {});
1197 } else {
1198 ref1 = args, [options, task, ...args] = ref1, [cb] = splice$1.call(args, -1);
1199 options = parser$4.load(options, this.jobDefaults);
1200 }
1201 job = {options, task, args, cb};
1202 options.priority = this._sanitizePriority(options.priority);
1203 if (options.id === this.jobDefaults.id) {
1204 options.id = `${options.id}-${this._randomIndex()}`;
1205 }
1206 if (this.jobStatus(options.id) != null) {
1207 if (typeof job.cb === "function") {
1208 job.cb(new Bottleneck.prototype.BottleneckError(`A job with the same id already exists (id=${options.id})`));
1209 }
1210 return false;
1211 }
1212 this._states.start(options.id); // RECEIVED
1213 this.Events.trigger("debug", `Queueing ${options.id}`, {args, options});
1214 return this._submitLock.schedule(async() => {
1215 var blocked, e, reachedHWM, shifted, strategy;
1216 try {
1217 ({reachedHWM, blocked, strategy} = (await this._store.__submit__(this.queued(), options.weight)));
1218 this.Events.trigger("debug", `Queued ${options.id}`, {args, options, reachedHWM, blocked});
1219 } catch (error1) {
1220 e = error1;
1221 this._states.remove(options.id);
1222 this.Events.trigger("debug", `Could not queue ${options.id}`, {
1223 args,
1224 options,
1225 error: e
1226 });
1227 if (typeof job.cb === "function") {
1228 job.cb(e);
1229 }
1230 return false;
1231 }
1232 if (blocked) {
1233 this._drop(job);
1234 return true;
1235 } else if (reachedHWM) {
1236 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;
1237 if (shifted != null) {
1238 this._drop(shifted);
1239 }
1240 if ((shifted == null) || strategy === Bottleneck.prototype.strategy.OVERFLOW) {
1241 if (shifted == null) {
1242 this._drop(job);
1243 }
1244 return reachedHWM;
1245 }
1246 }
1247 this._states.next(job.options.id); // QUEUED
1248 this._queues.push(options.priority, job);
1249 await this._drainAll();
1250 return reachedHWM;
1251 });
1252 }
1253
1254 schedule(...args) {
1255 var options, task, wrapped;
1256 if (typeof args[0] === "function") {
1257 [task, ...args] = args;
1258 options = parser$4.load({}, this.jobDefaults, {});
1259 } else {
1260 [options, task, ...args] = args;
1261 options = parser$4.load(options, this.jobDefaults);
1262 }
1263 wrapped = (...args) => {
1264 var cb, ref, returned;
1265 ref = args, [...args] = ref, [cb] = splice$1.call(args, -1);
1266 returned = task(...args);
1267 return (!(((returned != null ? returned.then : void 0) != null) && typeof returned.then === "function") ? this.Promise.resolve(returned) : returned).then(function(...args) {
1268 return cb(null, ...args);
1269 }).catch(function(...args) {
1270 return cb(...args);
1271 });
1272 };
1273 return new this.Promise((resolve, reject) => {
1274 return this.submit(options, wrapped, ...args, function(...args) {
1275 return (args[0] != null ? reject : (args.shift(), resolve))(...args);
1276 }).catch((e) => {
1277 return this.Events.trigger("error", e);
1278 });
1279 });
1280 }
1281
1282 wrap(fn) {
1283 var wrapped;
1284 wrapped = (...args) => {
1285 return this.schedule(fn, ...args);
1286 };
1287 wrapped.withOptions = (options, ...args) => {
1288 return this.schedule(options, fn, ...args);
1289 };
1290 return wrapped;
1291 }
1292
1293 async updateSettings(options = {}) {
1294 await this._store.__updateSettings__(parser$4.overwrite(options, this.storeDefaults));
1295 parser$4.overwrite(options, this.instanceDefaults, this);
1296 return this;
1297 }
1298
1299 currentReservoir() {
1300 return this._store.__currentReservoir__();
1301 }
1302
1303 incrementReservoir(incr = 0) {
1304 return this._store.__incrementReservoir__(incr);
1305 }
1306
1307 }
1308 Bottleneck.default = Bottleneck;
1309
1310 Bottleneck.Events = Events$4;
1311
1312 Bottleneck.version = Bottleneck.prototype.version = require$$7.version;
1313
1314 Bottleneck.strategy = Bottleneck.prototype.strategy = {
1315 LEAK: 1,
1316 OVERFLOW: 2,
1317 OVERFLOW_PRIORITY: 4,
1318 BLOCK: 3
1319 };
1320
1321 Bottleneck.BottleneckError = Bottleneck.prototype.BottleneckError = BottleneckError_1;
1322
1323 Bottleneck.Group = Bottleneck.prototype.Group = Group_1;
1324
1325 Bottleneck.RedisConnection = Bottleneck.prototype.RedisConnection = require$$2;
1326
1327 Bottleneck.IORedisConnection = Bottleneck.prototype.IORedisConnection = require$$3;
1328
1329 Bottleneck.Batcher = Bottleneck.prototype.Batcher = Batcher_1;
1330
1331 Bottleneck.prototype.jobDefaults = {
1332 priority: DEFAULT_PRIORITY,
1333 weight: 1,
1334 expiration: null,
1335 id: "<no-id>"
1336 };
1337
1338 Bottleneck.prototype.storeDefaults = {
1339 maxConcurrent: null,
1340 minTime: 0,
1341 highWater: null,
1342 strategy: Bottleneck.prototype.strategy.LEAK,
1343 penalty: null,
1344 reservoir: null,
1345 reservoirRefreshInterval: null,
1346 reservoirRefreshAmount: null
1347 };
1348
1349 Bottleneck.prototype.localStoreDefaults = {
1350 Promise: Promise,
1351 timeout: null,
1352 heartbeatInterval: 250
1353 };
1354
1355 Bottleneck.prototype.redisStoreDefaults = {
1356 Promise: Promise,
1357 timeout: null,
1358 heartbeatInterval: 5000,
1359 clientOptions: {},
1360 clusterNodes: null,
1361 clearDatastore: false,
1362 connection: null
1363 };
1364
1365 Bottleneck.prototype.instanceDefaults = {
1366 datastore: "local",
1367 connection: null,
1368 id: "<no-id>",
1369 rejectOnDrop: true,
1370 trackDoneStatus: false,
1371 Promise: Promise
1372 };
1373
1374 Bottleneck.prototype.stopDefaults = {
1375 enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.",
1376 dropWaitingJobs: true,
1377 dropErrorMessage: "This limiter has been stopped."
1378 };
1379
1380 return Bottleneck;
1381
1382 }).call(commonjsGlobal);
1383
1384 var Bottleneck_1 = Bottleneck;
1385
1386 var lib = Bottleneck_1;
1387
1388 return lib;
1389
1390})));