Node: async_hooks: context loss when awaiting a thenable

Created on 7 May 2019  路  8Comments  路  Source: nodejs/node

It seems async_hooks is losing context, in certain cases, when awaiting a thenable. This appears to occur in all major versions of Node.js with async_hooks available. See the code example and output for reference.

Within the then function on the thenable object, the trigger id is 0. Note that this _does not_ happen when awaiting a thenable as the first await within an async function.

cc @nodejs/diagnostics


Code example

const async_hooks = require('async_hooks')

const asyncHook = async_hooks.createHook({
  init (asyncId, type, triggerAsyncId) {
    log({
      event: 'init',
      asyncId,
      type,
      triggerAsyncId
    })
  },

  before (asyncId) {
    log({
      event: 'before',
      asyncId
    })
  },

  after (asyncId) {
    log({
      event: 'after',
      asyncId
    })
  }
})
asyncHook.enable()

function log (data) {
  process._rawDebug(JSON.stringify(data))
}

function tick () {
  return new Promise(setImmediate)
}

async function main () {
  await tick()
  await {
    then (fn) {
      log({
        executionAsyncId: async_hooks.executionAsyncId(),
        triggerAsyncId: async_hooks.triggerAsyncId(),
        message: 'these ids should not be zero'
      })
      setImmediate(fn)
    }
  }
}

main()


Output

{"event":"init","asyncId":2,"type":"PROMISE","triggerAsyncId":1}
{"event":"init","asyncId":3,"type":"PROMISE","triggerAsyncId":1}
{"event":"init","asyncId":4,"type":"Immediate","triggerAsyncId":1}
{"event":"init","asyncId":5,"type":"PROMISE","triggerAsyncId":3}
{"event":"before","asyncId":4}
{"event":"after","asyncId":4}
{"event":"before","asyncId":5}
{"event":"init","asyncId":6,"type":"PROMISE","triggerAsyncId":2}
{"event":"init","asyncId":7,"type":"PROMISE","triggerAsyncId":6}
{"event":"after","asyncId":5}
{"executionAsyncId":0,"triggerAsyncId":0,"message":"these ids should not be zero"}
{"event":"init","asyncId":8,"type":"Immediate","triggerAsyncId":0}
{"event":"before","asyncId":8}
{"event":"after","asyncId":8}
{"event":"before","asyncId":7}
{"event":"after","asyncId":7}

async_hooks feature request

All 8 comments

AFAIK there has never been support for thenables and thus I marked this as feature request.

Seems to me like a requirement for async_hooks to actually be useful. There are _many_ popular libraries that use the thenable pattern. In my particular case, we ran into knex using thenables internally, but in theory _any_ userland promise implementation should suffer from the same problem.

Adding diag-agenda to discuss if this should be considered a bug or feature request at the next meeting. Let me know if you disagree.

Yes, this is the same issue as I observed in #26064.

Duplicate of #26064

@Qard i deduplicated this, #22360 has the most conversation on this so i made that the diag-agenda item

Yes, this appears to be a duplicate. I _do_ still think this needs to be brought up in the diagnostics meeting though to figure out how to proceed. The AsyncResource fix is valid, but the fact that async_hooks continues to be considered experimental discourages the community from using it and therefore means a _huge_ chunk of the ecosystem will straight up break async_hooks currently.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stevenvachon picture stevenvachon  路  3Comments

jmichae3 picture jmichae3  路  3Comments

dfahlander picture dfahlander  路  3Comments

loretoparisi picture loretoparisi  路  3Comments

addaleax picture addaleax  路  3Comments