{ "source": "doc/api/domain.markdown", "modules": [ { "textRaw": "Domain", "name": "domain", "stability": 1, "stabilityText": "Experimental", "desc": "
Domains provide a way to handle multiple different IO operations as a\nsingle group. If any of the event emitters or callbacks registered to a\ndomain emit an error
event, or throw an error, then the domain object\nwill be notified, rather than losing the context of the error in the\nprocess.on('uncaughtException')
handler, or causing the program to\nexit with an error code.\n\n
This feature is new in Node version 0.8. It is a first pass, and is\nexpected to change significantly in future versions. Please use it and\nprovide feedback.\n\n
\nDue to their experimental nature, the Domains features are disabled unless\nthe domain
module is loaded at least once. No domains are created or\nregistered by default. This is by design, to prevent adverse effects on\ncurrent programs. It is expected to be enabled by default in future\nNode.js versions.\n\n
Any time an Error object is routed through a domain, a few extra fields\nare added to it.\n\n
\nerror.domain
The domain that first handled the error.error.domain_emitter
The event emitter that emitted an 'error' event\nwith the error object.error.domain_bound
The callback function which was bound to the\ndomain, and passed an error as its first argument.error.domain_thrown
A boolean indicating whether the error was\nthrown, emitted, or passed to a bound callback function.If domains are in use, then all new EventEmitter objects (including\nStream objects, requests, responses, etc.) will be implicitly bound to\nthe active domain at the time of their creation.\n\n
\nAdditionally, callbacks passed to lowlevel event loop requests (such as\nto fs.open, or other callback-taking methods) will automatically be\nbound to the active domain. If they throw, then the domain will catch\nthe error.\n\n
\nIn order to prevent excessive memory usage, Domain objects themselves\nare not implicitly added as children of the active domain. If they\nwere, then it would be too easy to prevent request and response objects\nfrom being properly garbage collected.\n\n
\nIf you want to nest Domain objects as children of a parent Domain,\nthen you must explicitly add them, and then dispose of them later.\n\n
\nImplicit binding routes thrown errors and 'error'
events to the\nDomain's error
event, but does not register the EventEmitter on the\nDomain, so domain.dispose()
will not shut down the EventEmitter.\nImplicit binding only takes care of thrown errors and 'error'
events.\n\n
Sometimes, the domain in use is not the one that ought to be used for a\nspecific event emitter. Or, the event emitter could have been created\nin the context of one domain, but ought to instead be bound to some\nother domain.\n\n
\nFor example, there could be one domain in use for an HTTP server, but\nperhaps we would like to have a separate domain to use for each request.\n\n
\nThat is possible via explicit binding.\n\n
\nFor example:\n\n
\n// create a top-level domain for the server\nvar serverDomain = domain.create();\n\nserverDomain.run(function() {\n // server is created in the scope of serverDomain\n http.createServer(function(req, res) {\n // req and res are also created in the scope of serverDomain\n // however, we'd prefer to have a separate domain for each request.\n // create it first thing, and add req and res to it.\n var reqd = domain.create();\n reqd.add(req);\n reqd.add(res);\n reqd.on('error', function(er) {\n console.error('Error', er, req.url);\n try {\n res.writeHead(500);\n res.end('Error occurred, sorry.');\n res.on('close', function() {\n // forcibly shut down any other things added to this domain\n reqd.dispose();\n });\n } catch (er) {\n console.error('Error sending 500', er, req.url);\n // tried our best. clean up anything remaining.\n reqd.dispose();\n }\n });\n }).listen(1337);\n});
\n"
}
],
"methods": [
{
"textRaw": "domain.create()",
"type": "method",
"name": "create",
"signatures": [
{
"return": {
"textRaw": "return: {Domain} ",
"name": "return",
"type": "Domain"
},
"params": []
},
{
"params": []
}
],
"desc": "Returns a new Domain object.\n\n
\n" } ], "classes": [ { "textRaw": "Class: Domain", "type": "class", "name": "Domain", "desc": "The Domain class encapsulates the functionality of routing errors and\nuncaught exceptions to the active Domain object.\n\n
\nDomain is a child class of [EventEmitter][]. To handle the errors that it\ncatches, listen to its error
event.\n\n
Run the supplied function in the context of the domain, implicitly\nbinding all event emitters, timers, and lowlevel requests that are\ncreated in that context.\n\n
\nThis is the most basic way to use a domain.\n\n
\nExample:\n\n
\nvar d = domain.create();\nd.on('error', function(er) {\n console.error('Caught error!', er);\n});\nd.run(function() {\n process.nextTick(function() {\n setTimeout(function() { // simulating some various async stuff\n fs.open('non-existent file', 'r', function(er, fd) {\n if (er) throw er;\n // proceed...\n });\n }, 100);\n });\n});
\nIn this example, the d.on('error')
handler will be triggered, rather\nthan crashing the program.\n\n
Explicitly adds an emitter to the domain. If any event handlers called by\nthe emitter throw an error, or if the emitter emits an error
event, it\nwill be routed to the domain's error
event, just like with implicit\nbinding.\n\n
This also works with timers that are returned from setInterval
and\nsetTimeout
. If their callback function throws, it will be caught by\nthe domain 'error' handler.\n\n
If the Timer or EventEmitter was already bound to a domain, it is removed\nfrom that one, and bound to this one instead.\n\n
\n" }, { "textRaw": "domain.remove(emitter)", "type": "method", "name": "remove", "signatures": [ { "params": [ { "textRaw": "`emitter` {EventEmitter | Timer} emitter or timer to be removed from the domain ", "name": "emitter", "type": "EventEmitter | Timer", "desc": "emitter or timer to be removed from the domain" } ] }, { "params": [ { "name": "emitter" } ] } ], "desc": "The opposite of domain.add(emitter)
. Removes domain handling from the\nspecified emitter.\n\n
The returned function will be a wrapper around the supplied callback\nfunction. When the returned function is called, any errors that are\nthrown will be routed to the domain's error
event.\n\n
var d = domain.create();\n\nfunction readSomeFile(filename, cb) {\n fs.readFile(filename, 'utf8', d.bind(function(er, data) {\n // if this throws, it will also be passed to the domain\n return cb(er, data ? JSON.parse(data) : null);\n }));\n}\n\nd.on('error', function(er) {\n // an error occurred somewhere.\n // if we throw it now, it will crash the program\n // with the normal line number and stack message.\n});
\n"
},
{
"textRaw": "domain.intercept(callback)",
"type": "method",
"name": "intercept",
"signatures": [
{
"return": {
"textRaw": "return: {Function} The intercepted function ",
"name": "return",
"type": "Function",
"desc": "The intercepted function"
},
"params": [
{
"textRaw": "`callback` {Function} The callback function ",
"name": "callback",
"type": "Function",
"desc": "The callback function"
}
]
},
{
"params": [
{
"name": "callback"
}
]
}
],
"desc": "This method is almost identical to domain.bind(callback)
. However, in\naddition to catching thrown errors, it will also intercept Error
\nobjects sent as the first argument to the function.\n\n
In this way, the common if (er) return callback(er);
pattern can be replaced\nwith a single error handler in a single place.\n\n
var d = domain.create();\n\nfunction readSomeFile(filename, cb) {\n fs.readFile(filename, 'utf8', d.intercept(function(data) {\n // note, the first argument is never passed to the\n // callback since it is assumed to be the 'Error' argument\n // and thus intercepted by the domain.\n\n // if this throws, it will also be passed to the domain\n // so the error-handling logic can be moved to the 'error'\n // event on the domain instead of being repeated throughout\n // the program.\n return cb(null, JSON.parse(data));\n }));\n}\n\nd.on('error', function(er) {\n // an error occurred somewhere.\n // if we throw it now, it will crash the program\n // with the normal line number and stack message.\n});
\n"
},
{
"textRaw": "domain.dispose()",
"type": "method",
"name": "dispose",
"desc": "The dispose method destroys a domain, and makes a best effort attempt to\nclean up any and all IO that is associated with the domain. Streams are\naborted, ended, closed, and/or destroyed. Timers are cleared.\nExplicitly bound callbacks are no longer called. Any error events that\nare raised as a result of this are ignored.\n\n
\nThe intention of calling dispose
is generally to prevent cascading\nerrors when a critical part of the Domain context is found to be in an\nerror state.\n\n
Once the domain is disposed the dispose
event will emit.\n\n
Note that IO might still be performed. However, to the highest degree\npossible, once a domain is disposed, further errors from the emitters in\nthat set will be ignored. So, even if some remaining actions are still\nin flight, Node.js will not communicate further about them.\n\n
\n", "signatures": [ { "params": [] } ] } ], "properties": [ { "textRaw": "`members` {Array} ", "name": "members", "desc": "An array of timers and event emitters that have been explicitly added\nto the domain.\n\n
\n" } ] } ], "type": "module", "displayName": "Domain" } ] }