Hi,

In an asynchronous environment like node.js, can it be hard to handle 
errors, specially by the asynchronous nature of node.js. Exceptions is good 
for synchronous programming, but does not fit well into a more complex 
asynchronous environment. I have come up with a solution, and want your 
thoughts about it.

var error = require('error'), //my module
    context = error.context,
    errc = error.errc,
    severity = error.severity;

//Create a sink, a place there all log message will go to.
context.add.sink('console', {
  on_message: function (err) {
    //replace this with your favourite logging library
    console.log("Error in context " + err.context.name() + ": " + 
err.message);
  },
  severity: [0, 1, 2, 3, 4, 5, 6, 7, 8]
});

context.add.errorListener(Error, function (err, next) {
  //invoked only if the following statement is true: (err instanceof 
Error), therefore is polymorphism possible.
  err.log(); //call all sinks
  next(); //call next errorListener, if any
});

context.run(function () {
  require('fs').readFile(__filename, this.intercept(function(file) {
    //no error, lets throw one
    throw new Error("My custom error"); //will be caught, by by context. 
Will not crash the application.
  }));
  var makeError = true;
  require('http').createServer(function (request, response) {

    var httpContext = context.newContext('httpContext');
    httpContext.add.errorListener(errc.httpError, function (err, next) {
      //a errc.httpError was emitted. Lets display a error page for the 
user.
      response.writeHead(err.code, { 'Content-Type': 'text/plain' });
      response.end(err.message);
      next();
    });

    httpContext.run(function () {
      if (makeError= !makeError) { //every two
        throw new errc.httpError();
      }
      response.writeHead(200, { 'Content-Type': 'text/plain' });
      response.end('Hello World\n');
    });
  }).listen(8080);
});

//errc.httpError implementation. The method utility.extend will only make 
sure the object has some properties.
var http = require('http'),
    util = require('util'),
    utility = require('utility');

//base error for all errors.
function error(params) {
  utility.extend(this, {
    message: "Error"
  });
  Error.call(this, params.message);
  Error.captureStackTrace(this, this.constructor);
}
util.inherits(error, Error);

function httpError(params) {
  params = utility.extend(params, {
    code: 500
  });

  utility.extend(params, {
    message: params.code + " " + http.STATUS_CODES[params.code]
  });

  utility.extend(this, params);
  error.call(this, params);
}

util.inherits(httpError, error);

var api = {
  error: error,
  httpError: httpError
};

module.exports = api;
 
//severity implementation:
var api = {
  emergency:  0,
  alert:      1,
  critical:   2,
  error:      3,
  warning:    4,
  notice:     5,
  info:       6,
  debug:      7,
  trace:      8
};

module.exports = api;

OUTPUT:
Error in context Application: My custom error
Error in context Application.httpContext: 500 Internal Server Error (after 
you have visit localhost:8080 two times)

Application is the default name of the top context, therefore 
"Application.httpContext".


Everything connected to a context will only exist in it and all its 
sub-contexts, so any errorListener/sink which are added to httpContext will 
be invisible from all contexts above itself. Some variables is dynamically 
added to all errors as well, like a log method and the current context.


I see the following advantages:

- Greater error control together with nested error handlers, there 
polymorphism can be used, as in the example.
- Scope based. Every error-listener/sink is bound to the current context 
there it is created and all sub context.
- Simple to create new errors (see how httpError is created above) and 
severities.

and the following disadvantages:

- All code which may thrown must be wrapped within context.run or 
context.intercept.
- The performance may decrease a little. It depends on the reason that all 
errors must be routed up to the top context if none error listener ignore 
calling next(). All log message will also be written to all sinks up to the 
top context. However it should be a CPU bound task, so it should never be 
noticeable.


Thoughts? Any comment is grateful :-)


Thanks in advance!

-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nodejs@googlegroups.com
To unsubscribe from this group, send email to
nodejs+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Reply via email to