Skip to content

Commit c1e7baa

Browse files
committed
perf(router): skip empty response metadata work
1 parent 81410da commit c1e7baa

1 file changed

Lines changed: 68 additions & 56 deletions

File tree

storage/framework/core/router/src/stacks-router.ts

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,71 +1957,83 @@ function createMiddlewareHandler(routeKey: string, handler: StacksHandler): Rout
19571957
const reqId = enhancedReq._requestId as string | undefined
19581958
const startNs = enhancedReq._startNs as bigint | undefined
19591959
const durMs = startNs != null ? Number(process.hrtime.bigint() - startNs) / 1_000_000 : null
1960+
const after = enhancedReq._afterResponse
1961+
const requested = enhancedReq._responseHeaders
1962+
const frameworkMetadataApplied = response
1963+
&& (response as unknown as Record<symbol, unknown>)[FRAMEWORK_RESPONSE_METADATA_APPLIED] === true
1964+
// Framework JSON responses already carry their request id and security
1965+
// defaults from `formatJsonResult`. When no middleware requested later
1966+
// work, leave the native Headers object untouched and avoid allocating
1967+
// the post-processing closure on the dominant success path.
1968+
const needsResponseMetadata = response && (
1969+
response.status >= 400
1970+
|| Array.isArray(after)
1971+
|| (requested && typeof requested === 'object')
1972+
|| durMs != null
1973+
|| !frameworkMetadataApplied
1974+
)
19601975

1961-
const setHeaders = (h: Headers) => {
1962-
/*
1963-
* Headers a middleware asked to have on the response.
1964-
*
1965-
* The middleware pipeline is pre-action only, so a middleware that has
1966-
* something to say *about the answer* - a rate limit's remaining count,
1967-
* a cache verdict, a deprecation notice - had nowhere to put it.
1968-
* Compression got a hard-coded post-action wrapper keyed on a
1969-
* `_compress` marker; everything else got nothing, and the workaround
1970-
* in an app is to wrap every action.
1971-
*
1972-
* So: a middleware writes `request._responseHeaders`, and they land
1973-
* here, before the router's own. The router's win a collision on
1974-
* purpose - `X-Request-ID` and `Server-Timing` are this layer's to
1975-
* state, and a middleware overwriting them breaks correlation.
1976-
*/
1977-
/*
1978-
* Callbacks a middleware asked to run once the answer is known.
1979-
*
1980-
* The header seam covers "put this on the response"; this covers
1981-
* "record that this happened", which is the other half of what a
1982-
* pre-action pipeline cannot do. Metrics are the obvious case: a
1983-
* middleware can time the start of a request and has no way to learn
1984-
* the status or the duration without one of these.
1985-
*
1986-
* Failures are swallowed on purpose. A metrics callback that throws
1987-
* must not turn a served request into a 500 - the observation is worth
1988-
* less than the thing being observed.
1989-
*/
1990-
const after = (enhancedReq)._afterResponse
1991-
if (Array.isArray(after)) {
1992-
for (const callback of after) {
1993-
try {
1994-
if (typeof callback === 'function')
1995-
callback({ status: response?.status ?? 0, durationMs: durMs ?? 0 })
1976+
if (needsResponseMetadata && typeof response.headers?.set === 'function') {
1977+
const setHeaders = (h: Headers) => {
1978+
/*
1979+
* Headers a middleware asked to have on the response.
1980+
*
1981+
* The middleware pipeline is pre-action only, so a middleware that has
1982+
* something to say *about the answer* - a rate limit's remaining count,
1983+
* a cache verdict, a deprecation notice - had nowhere to put it.
1984+
* Compression got a hard-coded post-action wrapper keyed on a
1985+
* `_compress` marker; everything else got nothing, and the workaround
1986+
* in an app is to wrap every action.
1987+
*
1988+
* So: a middleware writes `request._responseHeaders`, and they land
1989+
* here, before the router's own. The router's win a collision on
1990+
* purpose - `X-Request-ID` and `Server-Timing` are this layer's to
1991+
* state, and a middleware overwriting them breaks correlation.
1992+
*/
1993+
/*
1994+
* Callbacks a middleware asked to run once the answer is known.
1995+
*
1996+
* The header seam covers "put this on the response"; this covers
1997+
* "record that this happened", which is the other half of what a
1998+
* pre-action pipeline cannot do. Metrics are the obvious case: a
1999+
* middleware can time the start of a request and has no way to learn
2000+
* the status or the duration without one of these.
2001+
*
2002+
* Failures are swallowed on purpose. A metrics callback that throws
2003+
* must not turn a served request into a 500 - the observation is worth
2004+
* less than the thing being observed.
2005+
*/
2006+
if (Array.isArray(after)) {
2007+
for (const callback of after) {
2008+
try {
2009+
if (typeof callback === 'function')
2010+
callback({ status: response.status, durationMs: durMs ?? 0 })
2011+
}
2012+
catch { /* an observation is worth less than the request it observes */ }
19962013
}
1997-
catch { /* an observation is worth less than the request it observes */ }
19982014
}
1999-
}
20002015

2001-
const requested = (enhancedReq)._responseHeaders
2002-
if (requested && typeof requested === 'object') {
2003-
for (const [name, value] of Object.entries(requested as Record<string, unknown>)) {
2004-
if (typeof value === 'string')
2005-
h.set(name, value)
2016+
if (requested && typeof requested === 'object') {
2017+
for (const [name, value] of Object.entries(requested as Record<string, unknown>)) {
2018+
if (typeof value === 'string')
2019+
h.set(name, value)
2020+
}
20062021
}
2007-
}
20082022

2009-
const frameworkMetadataApplied = (response as unknown as Record<symbol, unknown>)[FRAMEWORK_RESPONSE_METADATA_APPLIED] === true
2010-
if (reqId && !frameworkMetadataApplied) h.set('X-Request-ID', reqId)
2011-
if (durMs != null) {
2012-
let timing = `total;dur=${durMs.toFixed(1)}`
2013-
// Append per-middleware timing entries. Chrome's network
2014-
// panel shows these as a stacked timeline under the response.
2015-
for (const t of middlewareTimings) {
2016-
timing += `, mw_${t.name};dur=${t.ms.toFixed(1)}`
2023+
if (reqId && !frameworkMetadataApplied) h.set('X-Request-ID', reqId)
2024+
if (durMs != null) {
2025+
let timing = `total;dur=${durMs.toFixed(1)}`
2026+
// Append per-middleware timing entries. Chrome's network
2027+
// panel shows these as a stacked timeline under the response.
2028+
for (const t of middlewareTimings) {
2029+
timing += `, mw_${t.name};dur=${t.ms.toFixed(1)}`
2030+
}
2031+
h.set('Server-Timing', timing)
20172032
}
2018-
h.set('Server-Timing', timing)
2033+
if (!frameworkMetadataApplied)
2034+
applySecurityHeaders(h)
20192035
}
2020-
if (!frameworkMetadataApplied)
2021-
applySecurityHeaders(h)
2022-
}
20232036

2024-
if (response && typeof (response).headers?.set === 'function') {
20252037
const isErrorJson = response.status >= 400
20262038
&& (response.headers.get('content-type') || '').includes('json')
20272039

0 commit comments

Comments
 (0)