userland implementation of https://github.com/joyent/node/issues/5243
Stability: 1 - Experimental
Local contexts provide a mechanism similar to thread-local storage in threaded programming. Contexts are created on namespaces and can be be nested.
Every namespace is created with a default context. The currently active
context on a namespace is available via
var context = require'context';var writer = contextcreateNamespace'writer';writerset'value' 0;var outer = writercreateContext;// writer.get('value') returns 0writerset'value' 1;// outer.get('value') returns 1// writer.get('value') returns 1processnextTickouterrunvar inner = writercreateContext;// writer.get('value') returns 1writerset'value' 2;// outer.get('value') returns 1// inner.get('value') returns 2// writer.get('value') returns 2;;setTimeout// runs with the default context, because nested contexts have endedconsole.logwriterget'value'; // prints 01000;
Returns a new namespace for context-sensitive values.
Look up an existing namespace.
List of available namespaces.
The Namespace groups local contexts, and encapsulates their nesting behavior, as well as containing the associated keys and values set on that namespace.
Returns the currently active context on a namespace.
Create a new local context.
Set a value on the current local context. Shorthand for
Look up a value on the current local context. Recursively searches from the innermost to outermost nested local context for a value associated with a given key.
A Context encapsulates the current nesting level and its associated
values. Contexts are derived from [EventEmitter], and have a life
cycle (which, for now, consists of the
end event when they're about to
go out of scope). Contexts are created exclusively via Namespaces.
Run a function within the specified local context. Shortcut for
Bind a function to the specified local context. Works analagously to
Set a value on the specified local context.
Look up a value on only the specified local context -- doesn't fall through to containing scopes.
The domains mechanism is a useful tool for adding context to errors raised in asynchronous call chains (or, if you like living dangerously / tempting the wrath of @isaacs, to recover from errors without restarting your services). It also almost serves the purposes of developers who want to annotate async call chains with metadata or extra state (examples: logging, tracing / profiling, generic instrumentation), but due to the needs of error-handling, it doesn't quite generalize enough to be truly useful in this regard. There are modules that allow developers to do similar things when they have full control over their stacks (CrabDude/trycatch and Gozala/reducers, among many others), but none of these modules are a good fit for developers writing tooling meant to be dropped transparently into user code.
See also joyent/node#3733.
Here is a sketch at what the user-visible API might look like. My
original attempt at this used a slightly modified version of the domains
API with some special-purpose logic for dealing with nested contexts,
but allowing multiple distinct namespaces is actually simpler and trades
memory for execution time. It also makes it possible to special-case
behavior for specific namespaces (i.e. my hope would be that domains
would just become a specialized namespace, and
_nextDomainTick would be all that would be required to deal with
namespaces), although that isn't included here.
Here's an example of how the API might be used:
var context = require'context';// multiple contexts in usevar tracer = contextcreateNamespace'tracer';thisharvester = harvester;var trace = tracercreateContext;traceon'end'var transaction = traceget'transaction';thisharvesteremit'finished' transaction;;traceruncallback;;var active = traceractive;activesetname value;;