Last active
December 24, 2015 01:09
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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