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

support async hooks #88

Merged
merged 3 commits into from
Jun 11, 2020
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/proto.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Module dependencies.
*/

const { AsyncResource } = require('async_hooks')
var ResourceLockedError = require('./errors').ResourceLockedError
var ValidationError = require('./errors').Validation
var normalize = require('to-no-case')
Expand Down Expand Up @@ -242,6 +243,24 @@ exports.request = function (method, path) {
return fn(err, res)
}

// Captures the current async context by creating an async resource for the
// superagent request.
//
// This is necessary because async_hooks does not follow "Thenable" types,
// depsite promises being compatible with them. The "then" method is invoked
// asynchronously on a "nextTick", where the async context that originally
// created the "Thenable" object has been lost.
//
// By creating the async resource here and overriding the "then" method, we
// bind the request object to the async execution context, and can restore
// it via a call to runInAsyncScope in the overriden "then" function.
const asyncResource = new AsyncResource('com.segment.integration.Request')
const thenFunction = Reflect.get(req, 'then')
const thenAsyncHook = function then (resolve, reject) {
Copy link
Member

Choose a reason for hiding this comment

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

Interesting. Is the current implementation different than:

Suggested change
const thenAsyncHook = function then (resolve, reject) {
function thenAsyncHook (resolve, reject) {

Copy link
Author

Choose a reason for hiding this comment

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

I think in the current code the function will be named then, so it leaks less details about the hack we're doing.

const thenAsyncHook = function then () {}
console.log(thenAsyncHook.name)
console.log((function thenAsyncHook () {}).name)
$ node test.js
then
thenAsyncHook

Copy link
Member

Choose a reason for hiding this comment

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

Interesting thanks!

return asyncResource.runInAsyncScope(thenFunction, this, resolve, reject)
}

req.then = thenAsyncHook
return req
}

Expand Down