forked from limitd/limitdb
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #34 from auth0/fix_spinning_again_event_loop_lap
fix: Added a second timeout(1) to force spinning again the event loop lap …
- Loading branch information
Showing
5 changed files
with
178 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
services: | ||
redis: | ||
image: 'redis:6' | ||
command: --save "" --appendonly no | ||
ports: | ||
- "6379:6379" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Based on the work of Jeremy Martin: https://github.com/jmar777/cb | ||
// Added a second timeout(1) to force spinning again the event loop lap and verify if the initial operation has been successful | ||
module.exports = function(callback) { | ||
|
||
var cb = function() { | ||
if (timedout || (once && count)) return; | ||
count += 1; | ||
tid && clearTimeout(tid); | ||
|
||
var args = Array.prototype.slice.call(arguments); | ||
process.nextTick(function() { | ||
if (!errback) return callback.apply(this, args); | ||
args[0] ? errback(args[0]) : callback.apply(this, args.slice(1)); | ||
}); | ||
|
||
}, count = 0, once = false, timedout = false, errback, tid; | ||
|
||
cb.timeout = function(ms) { | ||
tid && clearTimeout(tid); | ||
tid = setTimeout(function() { | ||
// force another second timeout to verify if the operation has been successful | ||
// No need to clear timeout since it has been triggered | ||
tid = setTimeout(function() { | ||
cb(new TimeoutError(ms)); | ||
timedout = true; | ||
}, 1); | ||
}, ms - 1); | ||
return cb; | ||
}; | ||
|
||
cb.error = function(func) { errback = func; return cb; }; | ||
|
||
cb.once = function() { once = true; return cb; }; | ||
|
||
return cb; | ||
|
||
}; | ||
|
||
var TimeoutError = module.exports.TimeoutError = function TimeoutError(ms) { | ||
this.message = 'Specified timeout of ' + ms + 'ms was reached'; | ||
Error.captureStackTrace(this, this.constructor); | ||
}; | ||
TimeoutError.prototype = new Error; | ||
TimeoutError.prototype.constructor = TimeoutError; | ||
TimeoutError.prototype.name = 'TimeoutError'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
var assert = require('assert'), | ||
cb = require('../lib/cb'); | ||
|
||
function invokeAsync(callback) { | ||
setTimeout(function() { | ||
callback(null, 'foo'); | ||
}, 100); | ||
} | ||
|
||
function invokeAsyncError(callback) { | ||
setTimeout(function() { | ||
callback(new Error()); | ||
}, 100); | ||
} | ||
|
||
function invokeAsyncTwice(callback) { | ||
setTimeout(function() { | ||
callback(null, 'foo'); | ||
callback(null, 'foo'); | ||
}, 100); | ||
} | ||
|
||
describe('cb(callback)', function() { | ||
|
||
it('should invoke the provided callback', function(done) { | ||
invokeAsync(cb(function(err, res) { | ||
assert.strictEqual(res, 'foo'); | ||
done(); | ||
})); | ||
}); | ||
|
||
it('shouldn\'t mess with errors', function(done) { | ||
invokeAsyncError(cb(function(err, res) { | ||
assert(err); | ||
done(); | ||
})); | ||
}); | ||
|
||
it('should allow multiple executions', function(done) { | ||
var count = 0; | ||
invokeAsyncTwice(cb(function(err, res) { | ||
count++; | ||
if (count === 2) done(); | ||
})); | ||
}); | ||
|
||
}); | ||
|
||
describe('cb(callback).timeout(ms)', function() { | ||
|
||
it('should complete successfully within timeout period', function(done) { | ||
invokeAsync(cb(function(err, res) { | ||
assert.strictEqual(res, 'foo'); | ||
done(); | ||
}).timeout(200)); | ||
}); | ||
|
||
it('should complete with an error after timeout period', function(done) { | ||
invokeAsync(cb(function(err, res) { | ||
assert(err); | ||
done(); | ||
}).timeout(50)); | ||
}); | ||
|
||
it('error resulting from a timeout should be instanceof cb.TimeoutError', function(done) { | ||
invokeAsync(cb(function(err, res) { | ||
assert(err instanceof cb.TimeoutError); | ||
done(); | ||
}).timeout(50)); | ||
}); | ||
}); | ||
|
||
describe('cb(callback).error(errback)', function() { | ||
|
||
it('should skip the err argument when invoking callback', function(done) { | ||
invokeAsync(cb(function(res) { | ||
assert.strictEqual(res, 'foo'); | ||
done(); | ||
}).error(assert.ifError)); | ||
}); | ||
|
||
it('should pass errors to provided errback', function(done) { | ||
invokeAsyncError(cb(function(res) { | ||
throw new Error('should not be invoked'); | ||
}).error(function(err) { | ||
assert(err); | ||
done(); | ||
})); | ||
}); | ||
|
||
}); | ||
|
||
describe('cb(callback).error(errback).timeout(ms)', function() { | ||
|
||
it('should skip the err argument when invoking callback', function(done) { | ||
invokeAsync(cb(function(res) { | ||
assert.strictEqual(res, 'foo'); | ||
done(); | ||
}).error(assert.ifError).timeout(200)); | ||
}); | ||
|
||
it('should pass timeout error to provided errback', function(done) { | ||
invokeAsyncError(cb(function(res) { | ||
throw new Error('should not be invoked'); | ||
}).error(function(err) { | ||
assert(err); | ||
done(); | ||
}).timeout(50)); | ||
}); | ||
|
||
}); | ||
|
||
describe('cb(callback).once()', function() { | ||
|
||
it('should allow multiple executions', function(done) { | ||
var count = 0; | ||
invokeAsyncTwice(cb(function(err, res) { | ||
count++; | ||
assert.notEqual(count, 2); | ||
setTimeout(done, 100); | ||
}).once()); | ||
}); | ||
|
||
}); |