summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormegawac <megawac@gmail.com>2016-11-08 23:13:33 -0500
committermegawac <megawac@gmail.com>2016-11-08 23:23:38 -0500
commit76daaef03203f4a8be37608ffca0020d3b174751 (patch)
tree35c6f30694f3b3c5a7b6770ae8c7965e147f5a31
parent9cc01fd30dc05e4df43a6ec67b3fbd5d44869457 (diff)
downloadasync-76daaef03203f4a8be37608ffca0020d3b174751.tar.gz
Initial token bucket implementation (#1314)
-rw-r--r--lib/internal/TokenBucket.js38
1 files changed, 38 insertions, 0 deletions
diff --git a/lib/internal/TokenBucket.js b/lib/internal/TokenBucket.js
new file mode 100644
index 0000000..011d13e
--- /dev/null
+++ b/lib/internal/TokenBucket.js
@@ -0,0 +1,38 @@
+import DLL from './DoublyLinkedList';
+
+/**
+ * An internal implementation of [Token Bucket](https://en.wikipedia.org/wiki/Token_bucket)
+ * for rate-limiting/traffic shaping. Our token bucket starts with a slight twist from the
+ * conventional token bucket, in which it starts with bucketSize tokens already available.
+ *
+ * @param {Number} bucketSize - the maximum number of items (inclusive) which can be queued in
+ * a interval of time.
+ * @param {Number} interval - the period in miliseconds to stop tracking a sent item
+ */
+export function TokenBucket(bucketSize, interval) {
+ this.bucketSize = bucketSize;
+ this.interval = interval;
+ this.queue = new DLL();
+ this.queued = 0; // Number of items sent + size of queue
+}
+
+// Enqueue an operation to be executed when the rate limit is not exceeded.
+TokenBucket.prototype.enqueue = function(operation) {
+ this.queued++;
+ if (this.queued <= this.bucketSize) {
+ operation();
+ } else {
+ this.queue.push(operation);
+ }
+
+ // after interval, decrement the queued count and call a queued operation (if bucket is full)
+ setTimeout(onIntervalComplete, this.interval, this);
+}
+
+function onIntervalComplete(bucket) {
+ bucket.queued--;
+ if (bucket.queue.length > 0) {
+ // call first queued operation
+ (bucket.queue.shift())();
+ }
+}