Created
June 10, 2012 09:53
-
-
Save AndreasMadsen/2904724 to your computer and use it in GitHub Desktop.
domain bug and design?
This file contains hidden or 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
var domain = require('domain'); | |
var url = require('url'); | |
var util = require('util'); | |
var events = require('events'); | |
/* hack */ | |
domain.Domain.prototype.run = function (fn) { | |
var active = this; | |
// sync thrown errors needs be be catch and deleayed by process.nextTick. | |
// This allow the function (fn) to return an error handler. | |
try { | |
return active.bind(fn)(); | |
} catch (er) { | |
util._extend(er, { | |
domain: active, | |
domain_thrown: true | |
}); | |
process.nextTick(function () { | |
active.emit('error', er); | |
}); | |
} | |
}; | |
/* */ | |
function Request(req, res) { | |
events.EventEmitter.call(this); | |
// lets hope this is safe :D | |
var self = this; | |
this.domain = domain.create(); | |
// add http request objects to domain | |
this.req = req; | |
this.res = res; | |
// this will acturlly throw because it checks req.domain | |
// unless we do the if check | |
if (req) this.domain.add(req); | |
if (res) this.domain.add(res); | |
// any domain error will be relayed to the request object itself | |
this.domain.on('error', function (error) { | |
// !!! - is this a bug? - fix is below | |
// No matter how much this is delayed it will throw and result in | |
// an infinity event loop, because the constructor never returned | |
// its own this object. | |
// setTimeout(function() { | |
// The only way to go around this is to wrap domain.rum in an try | |
// catch, but the purpose of domain is not to do that. At least | |
// not manually. See hack above! | |
self.emit('error', error); | |
//}, 200); | |
}); | |
// any error should be catched | |
return this.domain.run((function () { | |
this.internal(); | |
}).bind(this)); | |
} | |
util.inherits(Request, events.EventEmitter); | |
Request.prototype.internal = function () { | |
this.url = url.parse(this.req.url); | |
}; | |
// !!! - is there a better pattern? | |
// execute function (fn) in domain wrapper, use it only on public functions | |
function wrap(fn) { | |
return function () { | |
// Note that in this case, the try catch inside the domain.run hack | |
// has no purpose, since the user has time to attach an error handler. | |
this.domain.run(fn.bind(this)); | |
}; | |
} | |
Request.prototype.parse = wrap(function () { | |
return this.url.hostname; | |
}); | |
Request.prototype.destroy = wrap(function () { | |
this.domain.dispose(); | |
}); | |
/// require land | |
// Somehow it happend that req wasn't set | |
// It dosn't matter how, this is just an example | |
var r = new Request(undefined, undefined); | |
// lets attach an error handler as fast as possibol | |
r.on('error', function (error) { | |
console.error(error.stack); | |
r.destroy(); | |
}); | |
// will fail since r.url is undefined | |
console.log('url parse:', r.parse()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment