Skip to content

Instantly share code, notes, and snippets.

@othiym23
Last active December 24, 2015 01:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save othiym23/6721743 to your computer and use it in GitHub Desktop.
Save othiym23/6721743 to your computer and use it in GitHub Desktop.
Works with async-listener polyfill, fails under https://github.com/trevnorris/node/tree/flippin-tick-thing.
var assert = require('assert');
/**
*
*
*
*
* SETUP AND BOILERPLATE
*
*
*
*/
if (!process.addAsyncListener) require('async-listener');
/*
* CLS code
*/
function Namespace () {
this.active = Object.create(null);
this._stack = [];
this.id = null;
}
Namespace.prototype.set = function (key, value) {
this.active[key] = value;
return value;
};
Namespace.prototype.get = function (key) {
return this.active[key];
};
Namespace.prototype.enter = function (context) {
assert.ok(context, "context must be provided for entering");
this._stack.push(this.active);
this.active = context;
};
Namespace.prototype.exit = function (context) {
assert.ok(context, "context must be provided for exiting");
if (this.active === context) {
assert.ok(this._stack.length, "can't remove top context");
this.active = this._stack.pop();
return;
}
var index = this._stack.lastIndexOf(context);
assert.ok(index >= 0, "context not currently entered; can't exit");
assert.ok(index, "can't remove top context");
this.active = this._stack[index - 1];
this._stack.length = index - 1;
};
Namespace.prototype.createContext = function () {
return Object.create(this.active);
};
Namespace.prototype.bind = function (fn, context) {
if (!context) context = this.active;
var self = this;
return function () {
self.enter(context);
try {
return fn.apply(this, arguments);
}
finally {
self.exit(context);
}
};
};
function create(name) {
assert.ok(name, "namespace must be given a name!");
var namespace = new Namespace(name);
namespace.id = process.addAsyncListener(
function () {
return namespace.active;
},
{
before : function (context, domain) { namespace.enter(domain); },
after : function (context, domain) { namespace.exit(domain); }
}
);
return namespace;
}
/*
* Transaction code
*/
var id = 1337;
function Transaction() { this.id = id++; }
/*
* Tracer code
*/
var namespace = create("__NR_tracer");
function getTransaction() {
var state = namespace.get('state');
if (state) return state.transaction;
}
function transactionProxy(handler) {
return function wrapTransactionInvocation() {
var state = {transaction : new Transaction()};
var context = namespace.createContext();
context.state = state;
return namespace.bind(handler, context).apply(this, arguments);
};
}
/**
*
*
*
*
* TEST
*
*
*
*/
function handler(id) {
assert.ok(getTransaction(), "transaction should be visible");
assert.equal(getTransaction().id, id, "transaction matches");
}
var first;
assert.ok(!getTransaction(), "transaction should not yet be visible");
var proxied = transactionProxy(function () {
assert.ok(getTransaction(), "transaction should be visible");
first = getTransaction().id;
process.nextTick(function () { handler(first); });
});
proxied();
process.nextTick(transactionProxy(function () {
assert.ok(getTransaction(), "transaction should be visible");
var second = getTransaction().id;
assert.notEqual(first, second, "different transaction IDs");
process.nextTick(function () { handler(second); });
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment