Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async hooks based context tracking #538

Merged
merged 1 commit into from
Aug 30, 2017
Merged

Async hooks based context tracking #538

merged 1 commit into from
Aug 30, 2017

Conversation

matthewloring
Copy link
Contributor

@matthewloring matthewloring commented Aug 10, 2017

Introduces a lower overhead, more correct context tracking
mechanism based on async hooks that is available when using the
trace agent on newer versions of node (>=8). To enable async
hooks based context, set the GCLOUD_TRACE_NEW_CONTEXT environment
variable. This change is not expected to have observable behavior
difference but due to the nature of context propagation it is
difficult to say for sure without real world testing.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Aug 10, 2017
@kjin kjin self-requested a review August 11, 2017 17:14
@matthewloring matthewloring requested a review from ofrobots August 12, 2017 04:35
@matthewloring
Copy link
Contributor Author

I'm still working through the right test plan for this and I'm not sold on the way namespaces are represented in the async hook based implementation but all the high level structure is there and the tests are passing. I would be interested to get some early feedback on this, especially on the required changes to the tests (grpc required the most invasive changes).

src/trace-api.js Outdated
@@ -165,11 +166,17 @@ TraceAgent.prototype.runInRootSpan = function(options, fn) {
// Create a new root span, and invoke fn with it.
var traceId = incomingTraceContext.traceId || (uuid.v4().split('-').join(''));
var parentId = incomingTraceContext.spanId || '0';
var frameOffset;
if (semver.satisfies(process.version, '>=8')) {

This comment was marked as spam.

This comment was marked as spam.

Copy link
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still looking.. some initial comments.

index.js Outdated
@@ -20,7 +20,9 @@ var filesLoadedBeforeTrace = Object.keys(require.cache);

// Load continuation-local-storage first to ensure the core async APIs get
// patched before any user-land modules get loaded.
require('continuation-local-storage');
if (require('semver').satisfies(process.version, '<8')) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
@@ -0,0 +1,146 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.

This comment was marked as spam.

This comment was marked as spam.

src/trace-api.js Outdated
@@ -169,7 +172,8 @@ TraceAgent.prototype.runInRootSpan = function(options, fn) {
options.name, /* Span name */
parentId, /* Parent's span ID */
true, /* Is root span */
options.skipFrames ? options.skipFrames + 2 : 2);
options.skipFrames ?
options.skipFrames + ROOT_SPAN_STACK_OFFSET : ROOT_SPAN_STACK_OFFSET);

This comment was marked as spam.

This comment was marked as spam.

// Monkeypatch the monkeypatcher
var oldIt = global.it;
global.it = function it(title, fn) {
return oldIt.call(this, title, cls.createNamespace().bind(fn));

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
// Core Zone Api

function Context() {
this.properties = {};

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated

Context.prototype.run = function(cb, applyThis, applyArgs) {
const oldContext = current;
current = new Context();

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

Namespace.prototype.run = function(cb) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

Namespace.prototype.runAndReturn = function(cb) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

Namespace.prototype.bind = function(cb) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

Namespace.prototype.runAndReturn = function(cb) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

Namespace.prototype.bindEmitter = function(ee) {

This comment was marked as spam.

This comment was marked as spam.

var logger = require('@google-cloud/common').logger;
var trace = require('../..');
var cls = require('../../src/cls.js');
if (semver.satisfies(process.version, '>=8')) {
// Monkeypatch the monkeypatcher

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@matthewloring
Copy link
Contributor Author

It looks like appveyor is hanging on hiredis compilation but everything else looks clean. Comments should be addressed. I think this is ready for another look. @kjin @ofrobots

@@ -19,7 +19,7 @@ before_install:
- psql -c "alter user postgres with password 'Password12!';" -U postgres

env:
- CXX=g++-4.8
- CXX=g++-4.8 GCLOUD_TRACE_NEW_CONTEXT=1

This comment was marked as spam.

This comment was marked as spam.

appveyor.yml Outdated
@@ -25,6 +25,7 @@ install:
- ps: cd ..\..\..\..
# set GCLOUD_PROJECT

This comment was marked as spam.

This comment was marked as spam.

@@ -20,7 +20,10 @@ var filesLoadedBeforeTrace = Object.keys(require.cache);

// Load continuation-local-storage first to ensure the core async APIs get
// patched before any user-land modules get loaded.
require('continuation-local-storage');
if (require('semver').satisfies(process.version, '<8') &&

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
return res;
};

Namespace.prototype.runAndReturn = function(fn) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
}
};

var n = null;

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
const contexts = {};
var current = {};

const hook = asyncHook.createHook({init, before, after, destroy});

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
const asyncHook = require('async_hooks');

const wrappedSymbol = Symbol('context_wrapped');
const contexts = {};

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated

function Namespace() {}

Namespace.prototype.get = function(k) {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
return cb;
}
const boundContext = current;
const wrapped = cb.length === 0 ? function() {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated

Namespace.prototype.bindEmitter = function(ee) {
for (var method of eventEmitterMethods) {
patchEventEmitterMethod(ee, method, this);

This comment was marked as spam.

This comment was marked as spam.

Copy link
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry.. butter fingers

@matthewloring
Copy link
Contributor Author

@ofrobots All comments should be addressed. PTAL.

src/cls-ah.js Outdated
let contexts = {};
let current = {};

const hook = asyncHook.createHook({init, before, destroy});

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
function Namespace() {}

Namespace.prototype.get = function(k) {
return current ? current[k] : undefined;

This comment was marked as spam.

This comment was marked as spam.

Copy link
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM w/ nits.

src/cls-ah.js Outdated
return cb;
}
const boundContext = current;
const wrapped = function contextWrapper() {

This comment was marked as spam.

This comment was marked as spam.

src/cls-ah.js Outdated
const eventEmitterMethods =
[ 'addListener', 'on', 'once', 'prependListener', 'prependOncelistener' ];

Namespace.prototype.bindEmitter = function(ee) {

This comment was marked as spam.

This comment was marked as spam.

Introduces a lower overhead, more correct context tracking
mechanism based on async hooks that is available when using the
trace agent on newer versions of node (>=8). To enable async
hooks based context, set the GCLOUD_TRACE_NEW_CONTEXT environment
variable. This change is not expected to have observable behavior
difference but due to the nature of context propagation it is
difficult to say for sure without real world testing.
@matthewloring matthewloring changed the title [WIP]: Experiment with async hooks based context tracking Async hooks based context tracking Aug 29, 2017
@matthewloring matthewloring merged commit 87e4254 into googleapis:master Aug 30, 2017
@matthewloring matthewloring deleted the cls branch August 30, 2017 02:10
matthewloring added a commit that referenced this pull request Aug 30, 2017
Introduces a lower overhead, more correct context tracking
mechanism based on async hooks that is available when using the
trace agent on newer versions of node (>=8). To enable async
hooks based context, set the GCLOUD_TRACE_NEW_CONTEXT environment
variable. This change is not expected to have observable behavior
difference but due to the nature of context propagation it is
difficult to say for sure without real world testing.

PR-URL: #538
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants