Skip to content

Commit

Permalink
1.1.0 changeSettings, null cb, CS 1.7.x
Browse files Browse the repository at this point in the history
  • Loading branch information
SGrondin committed Mar 16, 2014
1 parent 1bf8c1a commit b264450
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 71 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
bottleneck
==========

Bottleneck is a simple and efficient Asynchronous Rate Limiter for Node.JS. When dealing with services with limited resources, it's important to ensure that they don't become overloaded. Bottleneck handles that case in a fast and clean way.
Bottleneck is a simple and efficient Asynchronous Rate Limiter for Node.JS and the browser. When dealing with services with limited resources, it's important to ensure that they don't become overloaded. Bottleneck is the easiest solution as it doesn't add any complexity to the code.

Databases, file systems, network access, APIs, etc. are all services that can easily be overwhelmed.


#Install
Expand Down Expand Up @@ -43,10 +45,16 @@ limiter.submit(someAsyncCall, arg1, arg2, argN, callback);
```
And now you can be assured that someAsyncCall will follow the rate guidelines!

If a callback isn't necessary, pass ```null``` instead.

###stopAll
```javascript
limiter.stopAll();
```
Cancels all queued up requests and prevents additonal requests from being submitted.


###changeSettings
```javascript
limiter.changeSettings(maxNb, minTime)
```
Same parameters as the constructor, pass ```null``` to skip a parameter.
60 changes: 35 additions & 25 deletions bottleneck.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Generated by CoffeeScript 1.6.3
// Generated by CoffeeScript 1.7.1
(function() {
var Bottleneck,
__slice = [].slice;
Expand All @@ -8,48 +8,56 @@
function Bottleneck(maxNb, minTime) {
this.maxNb = maxNb != null ? maxNb : 0;
this.minTime = minTime != null ? minTime : 0;
this.nextRequest = Date.now();
this.nbRunning = 0;
this.queue = [];
this.timeouts = [];
this._nextRequest = Date.now();
this._nbRunning = 0;
this._queue = [];
this._timeouts = [];
}

Bottleneck.prototype._tryToRun = function() {
var done, next, wait,
_this = this;
if ((this.nbRunning < this.maxNb || this.maxNb <= 0) && this.queue.length > 0) {
this.nbRunning++;
wait = Math.max(this.nextRequest - Date.now(), 0);
this.nextRequest = Date.now() + wait + this.minTime;
next = this.queue.shift();
var done, next, wait;
if ((this._nbRunning < this.maxNb || this.maxNb <= 0) && this._queue.length > 0) {
this._nbRunning++;
wait = Math.max(this._nextRequest - Date.now(), 0);
this._nextRequest = Date.now() + wait + this.minTime;
next = this._queue.shift();
done = false;
return this.timeouts.push(setTimeout(function() {
return next.task.apply({}, next.args.concat(function() {
if (!done) {
done = true;
_this.nbRunning--;
_this._tryToRun();
return next.cb.apply({}, Array.prototype.slice.call(arguments, 0));
}
}));
}, wait));
return this._timeouts.push(setTimeout((function(_this) {
return function() {
return next.task.apply({}, next.args.concat(function() {
var _ref;
if (!done) {
done = true;
_this._nbRunning--;
_this._tryToRun();
return (_ref = next.cb) != null ? _ref.apply({}, Array.prototype.slice.call(arguments, 0)) : void 0;
}
}));
};
})(this), wait));
}
};

Bottleneck.prototype.submit = function() {
var args, cb, task, _i;
task = arguments[0], args = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), cb = arguments[_i++];
this.queue.push({
this._queue.push({
task: task,
args: args,
cb: cb
});
return this._tryToRun();
};

Bottleneck.prototype.changeSettings = function(maxNb, minTime) {
this.maxNb = maxNb != null ? maxNb : this.maxNb;
this.minTime = minTime != null ? minTime : this.minTime;
return this;
};

Bottleneck.prototype.stopAll = function() {
var a, _i, _len, _ref;
_ref = this.timeouts;
_ref = this._timeouts;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
a = _ref[_i];
clearTimeout(a);
Expand All @@ -66,7 +74,8 @@
}).call(this);

},{}],2:[function(require,module,exports){
var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};// Generated by CoffeeScript 1.6.3
(function (global){
// Generated by CoffeeScript 1.7.1
(function() {
module.exports = require("./Bottleneck");

Expand All @@ -76,4 +85,5 @@ var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ?

}).call(this);

}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Bottleneck":1}]},{},[2])
2 changes: 1 addition & 1 deletion bottleneck.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 32 additions & 24 deletions lib/Bottleneck.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bottleneck",
"version": "1.0.0",
"version": "1.1.0",
"description": "Async rate limiter",
"main": "lib/index.js",
"scripts": {
Expand All @@ -27,7 +27,7 @@
"url": "https://github.com/SGrondin/bottleneck/issues"
},
"devDependencies":{
"coffee-script": "*",
"coffee-script": "1.7.x",
"browserify": "*",
"uglify-js": "*"
}
Expand Down
31 changes: 15 additions & 16 deletions src/Bottleneck.coffee
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
class Bottleneck
constructor: (@maxNb=0, @minTime=0) ->
@nextRequest = Date.now()
@nbRunning = 0
@queue = []
@timeouts = []

@_nextRequest = Date.now()
@_nbRunning = 0
@_queue = []
@_timeouts = []
_tryToRun: ->
if (@nbRunning < @maxNb or @maxNb <= 0) and @queue.length > 0
@nbRunning++
wait = Math.max @nextRequest-Date.now(), 0
@nextRequest = Date.now() + wait + @minTime
next = @queue.shift()
if (@_nbRunning < @maxNb or @maxNb <= 0) and @_queue.length > 0
@_nbRunning++
wait = Math.max @_nextRequest-Date.now(), 0
@_nextRequest = Date.now() + wait + @minTime
next = @_queue.shift()
done = false
@timeouts.push setTimeout () =>
@_timeouts.push setTimeout () =>
next.task.apply {}, next.args.concat () =>
if not done
done = true
@nbRunning--
@_nbRunning--
@_tryToRun()
next.cb.apply {}, Array::slice.call arguments, 0
next.cb?.apply {}, Array::slice.call arguments, 0
, wait
submit: (task, args..., cb) ->
@queue.push {task, args, cb}
@_queue.push {task, args, cb}
@_tryToRun()

changeSettings: (@maxNb=@maxNb, @minTime=@minTime) -> @
stopAll: ->
(clearTimeout a for a in @timeouts)
(clearTimeout a for a in @_timeouts)
@_tryToRun = -> # Ugly, but it's that or more global state

module.exports = Bottleneck

0 comments on commit b264450

Please sign in to comment.