Skip to content

async_hooks use case: Async resource and stack isolation #62031

@kitten

Description

@kitten

Affected URL(s)

https://nodejs.org/api/async_hooks.html#async-hooks

Description of the problem

We're building an emulation tool for workerd's event loop / async resource isolation that aims to be similar in intention. In workerd (or Cloudflare Workers) they track both the event loop for each incoming request and resources it creates.

If the work per request cannot complete workerd issues as "Will never generate a response" error, see: https://developers.cloudflare.com/workers/observability/errors/#the-script-will-never-generate-a-response-errors

The cause of this is a bit abstract and separate from the intention;

  • Possible causes: For example, two requests share a new Promise, one request is cancelled, hence, the other can never resolve
  • General intention: Each request is isolated and shouldn't share async resources with another to guarantee that requests cannot stall (and presumably so requests can eventually more strongly be isolated; this does in theory prevent future bugs)
  • Implementation detail: As far as I'm aware, this is tracked by checking the event loop. If any request runs out of pending async tasks/resources, it has created/owns, and hasn't resolved, then this error is thrown

This creates a developer experience problem. Not only is it hard to emulate this exact check accurately (as far as I'm aware), it's hard to track why this error is thrown. In development for Expo, we'd instead like to track async resources and proactively create rules that emulate this behaviour while delivering more information on where or why the violation of a rule has occurred.

Long story short: The proof of concept code for this uses async_hooks's createHook with a small graph that attempts to keep track of where async resources are created and resolved: https://github.com/kitten/fiber-dev

The tests show which rules we'd like to enforce:

  • async resources created outside an isolated function shouldn't be used within
  • async resources created in one isolated function shouldn't be used within another
  • stalling async resources (e.g. unresolved promises) should lead to an error

While this slows things down marginally, it's useful to deliver more useful errors in development, before users take their server-side code to workerd in production.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions