Skip to content

fix: #775 — emit shim note when async_hooks is imported#787

Merged
TheHypnoo merged 1 commit into
mainfrom
fix/issue-775-async-hooks-shim-note
May 15, 2026
Merged

fix: #775 — emit shim note when async_hooks is imported#787
TheHypnoo merged 1 commit into
mainfrom
fix/issue-775-async-hooks-shim-note

Conversation

@TheHypnoo
Copy link
Copy Markdown
Contributor

Summary

Closes #775.

The node:async_hooks stub added in #754 is structural — it provides AsyncResource, AsyncLocalStorage, executionAsyncId, and createHook shapes so NestJS bootstrap compiles, but it does not track async context across await / setImmediate / process.nextTick. Anything that relies on AsyncLocalStorage for context propagation (Sentry request scopes, OpenTelemetry trace propagation, NestJS request-scoped providers, pino child loggers) compiles, runs, and silently loses context.

This PR mirrors the reflect-metadata 2a mitigation: a one-shot [perry] note: to stderr at compile time when async_hooks (or node:async_hooks) is imported.

  • New emit_async_hooks_shim_note() in crates/perry-hir/src/lower.rs, same AtomicBool::swap one-shot pattern as emit_reflect_metadata_shim_note().
  • Wired into lower_module_decl next to the reflect-metadata branch. Source is already normalized to strip the node: prefix, so a single source == "async_hooks" check covers both spellings.
  • Unlike the reflect-metadata branch, this one falls through (no return Ok(())) — the import still needs to bind AsyncLocalStorage / AsyncResource against the existing structural stub.

Real async-context tracking via tokio task_local! (or via Perry's promise/microtask scheduler) is the proper long-term fix; this is the minimum-viable mitigation so the silent-failure surface doesn't grow.

Test plan

  • cargo build --release -p perry-hir — clean.
  • cargo build --release -p perry — clean.
  • Compiled a fixture with import { AsyncLocalStorage } from "node:async_hooks" and confirmed the [perry] note: ... line prints once to stderr during the compile.
  • CI: lint, cargo-test, parity, compile-smoke, api-docs-drift, security-audit.

The `node:async_hooks` stub added in PR #754 is structural: it gives
NestJS bootstrap enough shape (`AsyncResource`, `AsyncLocalStorage`,
`executionAsyncId`, `createHook`) to compile, but does NOT track async
context across `await` / `setImmediate` / `process.nextTick`. Anything
that relies on `AsyncLocalStorage` for context propagation — Sentry
request scopes, OpenTelemetry trace propagation, NestJS request-scoped
providers, pino child loggers — compiles, runs, and silently loses
context.

Mirror the reflect-metadata 2a mitigation: emit a one-shot
`[perry] note:` to stderr at compile time when `async_hooks` (or
`node:async_hooks`) is imported, listing the implemented surface and
the silent-failure boundary. Same `AtomicBool::swap` pattern as
`emit_reflect_metadata_shim_note()`. Unlike reflect-metadata, the
import still falls through so `AsyncLocalStorage` / `AsyncResource`
keep binding against the structural stub.
@TheHypnoo TheHypnoo merged commit 11d9b90 into main May 15, 2026
9 checks passed
@TheHypnoo TheHypnoo deleted the fix/issue-775-async-hooks-shim-note branch May 15, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AsyncLocalStorage stub silently drops async context — emit shim diagnostic on async_hooks import

1 participant