async_hooks in node.js, illustrated

Irina Shestak
Aug 28, 2017 · 3 min read

async_hooks, the new and still experimental API that came out with node 8 got my attention a few weeks back, so I decided to do a bit of exploring as to what it can help me do.

Image for post
Image for post
async_hooks API in a gist

async_hooks API essentially makes it easier for you to track your resources (bye dtrace?). You start off by initializing it with an object of callbacks: init, before, after and destroy.

.

.

var asyncHooks = require('async_hooks')var hooks = {
init: init,
before: before,
after: after,
destroy: destroy
}
var asyncHook = asyncHooks.createHook(hooks)

async_hooks is based around a concept of resources. A resource triggers async_hooks callbacks from above to be called, and could be anything from TTYWRAP to SSLCONNECTION to the one you defined with the Embedder API (more on this later). If you were to write a server with http.createServer(), start the async_hooks API, and look at init callback’s resource, you will end up with these ones, for example:

var http = require('http')// asyncHook being defined in code snippet above
asyncHook.enable()
http.createServer(function (req, res) {
res.end('hello qts')
}).listen(8079)
function init (asyncId, type, triggerId) {
fs.writeSync(1, `${type} \n`)
}
Image for post
Image for post
resource examples on a sample GET request
Image for post
Image for post
async_hooks init callback

This init callback is probably the most interesting one — it allows you to access the current resource, and look into what caused it to trigger. This means you will eventually be able to create a nice structure to figure out what really goes on within your application.

Image for post
Image for post
create a trace on ‘init’, and group spans by their ‘triggerId’

I thought of this as a nice segue into tracing — accessing init's asyncId and triggerId, starting a timer to track your operation and eventually destroying it during a destroy. With that, I wrote on-async-hook, a simple async_hook trace emitter.

on-async-hook creates a trace when async_hooks calls their init callback, and groups resources based on their triggerId. I wanted to time operations, so on-async-hook trace structure also includes start and end time, which it then adds during init and removes ondestroy. A simple hello world server will end up with a trace like this, for example:

Image for post
Image for post
on-async-hook ‘hello world’ trace

If you are working with native C++ bindings, you may want to define your own resources. You could do that easily with the Embedder API. Here is an example setting this up with mafintosh’s utp-native library:

var AsyncResource = require('async_hooks').AsyncResource
var utp = require('utp-native')
var resource = new AsyncResource('UTPNative')var server = utp.createServer(function (socket) {
socket.pipe(socket)
})
server.listen(1337, function () {
var socket = utp.connect(1337)
resource.emitBefore()
socket.write('hello qts')
resource.emitAfter()
socket.on('data', function (data) {
console.log('resourceId', resource.asyncId())
console.log('triggerAsyncId', resource.triggerAsyncId())
console.log('this is my data ', data)
})
})
server.on('close', function () {
resource.emitDestroy()
})

async_hooks is still pretty experimental — things broke™, and API is possibly still changing (i.e. async_hooks.executionAsyncId() used to be async_hooks.currentId(), o/), but it’s pretty awesome to see node putting together new ways for us to monitor our applications.

  • Performance Timing API jasnell has been working on landed in node last week. This is pretty exciting news for your node application performance monitoring and I’d definitely suggest looking into it.
  • If you’re using async_hooks in production, there is an issue open for gathering some information.
  • Since async_hooks is only available starting node 8, I would also suggest to look into davidmarkclem’s async-tracer — it supports node’s previous versions.

Node.js Collection

Community-curated content for the millions of Node.js

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store