I'm going to make a few assumptions here.

1. domain.enter() and domain.exit() are intended for use by the node.js 
framework, not by application code
2. The domain stack is intended for use within an event, not to communicate 
between events
3. The normal use of the event stack is illustrated by how it works with 
nested domain.run() calls; as each run() exits, the stack is popped to 
activate the domain specified by the calling function.

If these are all correct, there's a bug in how the domain stack is 
processed when an error occurs.  Consider the following script:

"use strict";

var domain = require('domain');

function createDomain(name) {
    var d = domain.createDomain();
    d.name = name;
    d.on("error", handleError);
    return d;
}

function showStack(label) {
    console.log(label);
    console.log(domain._stack);
    console.log();
}

function handleError(error) {
    console.log("Error: " + error);
    console.log("Active domain is: " + process.domain.name);
    showStack("After error");
}
    
showStack("initial");

process.nextTick(function() {
    showStack("in new event");
});

var d1 = createDomain("d1");
var d2 = createDomain("d2");

d1.run(function() {
    d2.run(function() {
        showStack("before error");
        throw new Error("first");
    });
});

The output is 

initial
[]

before error
[ { members: [],
    name: 'd1',
    _events: { error: [Function: handleError] } },
  { members: [],
    name: 'd2',
    _events: { error: [Function: handleError] } } ]

Error: Error: first
Active domain is: d2
After error
[ { members: [],
    name: 'd1',
    _events: { error: [Function: handleError] } },
  { members: [],
    name: 'd2',
    _events: { error: [Function: handleError] } },
  { members: [],
    name: 'd2',
    _events: { error: [Function: handleError] } } ]

in new event
[ { members: [],
    name: 'd1',
    _events: { error: [Function: handleError] } } ]

That is, when the error occurs, both d1 and d2 are on the domain stack, 
with d2 being active.   d2 is pushed onto the stack for the error handler 
to run, and then popped, and d2 is popped again by the event cleanup code, 
but d1 remains on the stack, and is still present when the event loop's 
next tick runs.  This isn't as intended: the next event to run could come 
from anywhere, including code completely unaware of d1 and not intended to 
use domains at all.  This also represents a memory leak, since d1 will stay 
on the stack forever.

In fact, I can't currently think of a reason that the domain stack 
shouldn't be cleared at the end of event processing, leaving it empty for 
the next event, which can then enter the proper domain for the emitter 
which created it.

Reply via email to