Missing afterReponse hook when an error happens
Environment
windows 11 nitro 2.9.6 h3 1.11 - 1.12
Reproduction
https://stackblitz.com/edit/unjs-nitro-starter-bbtnhb?file=server%2Froutes%2Fthrow.ts,server%2Froutes%2Findex.ts,server%2Fplugins%2Flog.ts,package.json&title=Nitro%20Starter
index return an error and /throw throws an error. In both case, afterResponse isn't called
Describe the bug
There's a bug where throwing error in handlers prevent the afterResponse from being called.
Additional context
No response
Logs
No response
Upstream issue from https://github.com/unjs/h3/issues/790
Digging through the code, it looks like the root cause may be that nitro's onError handler actually sends the response https://github.com/nitrojs/nitro/blob/v2/src/runtime/error.ts#L82
This marks the event as handled, so h3 will not call the beforeResponse/afterResponse hooks https://github.com/unjs/h3/blob/v1/src/adapters/node.ts#L73
Maybe a solution could be to also trigger those hooks within the error handler, before and after the send calls.
Moving to the Web APIs for the server, after response stagge cannot be stably hooked on since the platform handles the response object when returned.
Two possible workarounds (although I don't suggest either unless you really have to):
- Wrap
Response.bodystream and wait for it to be finished - Use
event.node?.res.on("finished")hook
For an operation like sending error reports that might need to be ongoing until after response without blocking it, event.waitUntil can be used.
Could this still be fixed for beforeResponse or will that also be removed?
beforeResponse should work with the error handler in v2. Nitro hasn't migrated yet (on it) but if you can reproduce any issue with it and h3 only please feel free to open new issue 👍🏼
https://github.com/nitrojs/nitro/issues/3254
@pi0 how would you use event.waitUntil to update metrics?
I'm using afterResponse hook to increment prometheus metrics, something like this
httpRequestCount.inc({ method: req.method, route, status_code: res.statusCode })
httpRequestDuration.observe({ method: req.method, route, status_code: res.statusCode }, durationInSeconds)
if (res.statusCode >= 400) {
httpRequestErrors.inc({ method: req.method, route, status_code: res.statusCode })
}
})
but when an error occurs, as mentioned in this issue the counters don't increase. Is there a workaround for that?