You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 741135e
Browse filesBrowse the repository at this point in the historyBrowse files
fix(node): End Express layer spans when next is called (#24854)
- [x] If you've added code that should be tested, please add tests.
- [x] Ensure your code lints and the test suite passes (scoped to the
affected packages, see Testing below).
- [x] Link an issue if there is one related to your pull request.
Closes#24853
Express layer spans were ended on the tracing channel's `asyncEnd`,
which only fires once `next()` *returns*. Express runs the rest of the
chain synchronously inside `next()`, so every layer on the synchronous
chain kept its span open, together with the response `finish` listener
that `getSpanForLayer` registers, until the whole chain unwound. As a
result:
- Requests that pass through roughly 9 or more synchronous layers log
`MaxListenersExceededWarning: ... 11 finish listeners added to
[ServerResponse]`, one per request. Unsampled requests are affected too.
- Each middleware span absorbs the synchronous work of every downstream
layer. A no-op middleware reported 50ms when the route handler after it
did 50ms of synchronous work.
This PR ends the layer span on `asyncStart` instead: when the layer
calls `next()`, before the downstream layer runs. That matches what the
surrounding comments and the orchestrion config already describe.
- Layers that never call `next()` still end on the response `finish`.
These are route handlers and routers that handle the request themselves,
so router spans still enclose the handler they dispatch.
- The helper's later `asyncEnd` is a no-op, because `span.end()` is
idempotent.
- `next(err)` still marks the span as errored, because the channel
publishes `error` before `asyncStart`.
### Testing
New `node-integration-tests` suite `express/layer-span-end`, with 12
synchronous middleware and a handler that does 50ms of synchronous work.
It asserts that:
- every middleware span ends before the request handler span starts
- the response has fewer `finish` listeners than
`EventEmitter.defaultMaxListeners`
Both tests fail without the change (16 listeners, and middleware spans
ending about 51ms after the handler starts) and pass with it.
Ran locally on Node 24.18:
- `suites/express/**`: 15 files, 132 tests pass
- the other 44 suite directories that use Express: 51 files, 395 tests
pass
- `@sentry/server-utils` unit tests: 1152 pass
- `oxfmt --check` and `oxlint` on the changed files
I also checked Express 5 against the published 11.1.0 build with this
change applied: listeners went from 12 to 2, no warning, and span names
were unchanged. I couldn't run the Bun and Deno node-suite projects
locally.
---------
Co-authored-by: Nicolas Hrubec <nico.hrubec@sentry.io>
0 commit comments