stream-utils / raw-body

Get and validate the raw body of a readable stream

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AsyncResource never emits `destroy` hook

devoto13 opened this issue · comments

So to provide some context. I'm using Jest to write tests and I get bunch of warnings like below:

Jest has detected the following 3 open handles potentially keeping Jest from exiting:

  ●  bound-anonymous-fn

      79 |
      80 |       await request(app.getHttpServer())
    > 81 |         .post('/client-mapping')
         |          ^
      82 |         .set('Content-Type', 'application/json')
      83 |         .send(requestBody)
      84 |         .expect(200)

Jest has a feature to detect open handles and it uses async_hooks for that. Essentially, it registers the asyncId when it receives init hook and unregisters it gets destroy hook. If anything is still registered after the tests are run, then some async resource wasn't properly destroyed. Full implementation is here.

I've nailed down the warning to this library. Apparently, it creates the AsyncResource here, but it never calls .emitDestroy() and therefore never calls the destroy hook. According to the Node documentation, the hook must be called manually.

Thank you for reporting this! I think you may misunderstand the code in thia module, which is simply a polyfill for the AsyncResource.bind Node.js function. Effectively we are trying to preserve async context around an event emitter and implemented the documented pattern provided by Node.js: https://nodejs.org/api/async_context.html#integrating-asyncresource-with-eventemitter

The pattern Node.js is showing to use for event emitters does not call destroy anywhere, and I'm not sure if it is even possible. It is possible the Node.js documentation on how to use with EventEmitters is wrong, however, or even how Jest is tracking it could be wrong. It seems we may need to do some digging to determine the tright answer here, particularly as I am not an expert on the async hooks stuff. I would, however, be very reluctant to change away from the pattern Node.js documents to use with EventEmitters, however, snce the async hooks stuff changes (so I'd want to be sure we are using what Node.js pattern is blessed).

Hi @devoto13 I know you closed this, but I still, myself, reached out to both Node.js and Jest to better understand. I actually have heard back from Jest that it was a bug in Jest, and should be fixed in Jest 29+. I know you didn't provide any way for me to reproduce your situation, but I used this module + supertest + Jest to create a simple test and saw the same open handle warning printed in versions before Jest 29, but it's no longer there for this in 29.0.0 or higher. I am assuming you are running jest with the --detectOpenHandles option. If you are using a version of Jest lower than 29, then perhaps upgrading Jest will resolve this for you.

Hey @dougwilson, Thanks for looking into it further. Indeed, the issue no longer occurs with Jest 29+ in the setup you describe (I'm also using supertest). Surprisingly, we're still using Jest 28. Looks like they actually started to run GC after tests to make sure destroy is called for wrapped EventEmitters. Wasn't aware that it is possible to expose it without user explicitly passing in the flag... See jestjs/jest@1f72803.