Error-tracking software doesn't catch hapi application errors if an incoming request gets prematurely closed

未关闭
#4,567 2 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

  • #4580 来自 @puneetdixit200 —— 已关闭,未合并

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
需要澄清
活跃度
停滞
领域
api, backend

调研方向

首先运行提供的 Node.js 复现,使用 request error event 和 onPreResponse hooks,然后检查 request lifecycle 文档以及相关的 request-abort 处理。将其与未中止的请求进行比较,并确定预期的错误报告行为。完成的标准是,项目已就中止请求达成一致方向;如果接受代码更改,还应包含回归覆盖。

由索引模型根据 Issue 内容生成。

描述

bug
Runtime

Node.js

Runtime version

v25.7.0

Module version

v21.4.7

Last module version without issue

No response

Used with

Sentry, Rollbar, DataDog

Any other relevant information

Sentry, Rollbar, and DataDog support tracking errors in hapi applications, relying on either hapi's request error event or on onPreResponse lifecycle method. See:

What are you trying to achieve or the steps to reproduce?

Here is example code that reproduces an issue where an error thrown in a handler bypasses both the request error event and onPreResponse lifecycle method calls.

import Hapi from "@hapi/hapi";
import { setTimeout as sleep } from "node:timers/promises"

const server = Hapi.server({
    port: 3000,
    host: "localhost"
});

server.events.on({ name: "request", channels: ["error"] }, (request, event, tags) => {
    console.log("[server] on request error"); // NOT called
})

server.ext("onPreResponse", async (request, h) => {
   console.log("[server] onPreResponse"); // NOT called
   return request;
});

server.route({
    method: "GET",
    path: "/sleep/{seconds}/then-throw-error",
    handler: async (request, h) => {
        const { seconds } = request.params;
        for (let i = 0; i < seconds; i++) {
            console.log("[handler] Handling a request... (sleep %s)", i + 1);
            await sleep(1_000);
        }
        console.log("[handler] Throwing error");
        throw new Error("Boom!");
    }
});

await server.start();
console.log("[server] Running on %s", server.info.uri);

try {
    console.log("[fetch] Making a request");
    await fetch("http://localhost:3000/sleep/5/then-throw-error", { signal: AbortSignal.timeout(1_000) });
} catch (error) {
    if (error.name === "TimeoutError") {
        console.log("[fetch] Stopped waiting for the response");
    } else {
        console.log(error);
    }
}
What was the result you got?

Here is the output produced by the example code:

[server] Running on http://localhost:3000
[fetch] Making a request
[handler] Handling a request... (sleep 1)
[fetch] Stopped waiting for the response
[handler] Handling a request... (sleep 2)
[handler] Handling a request... (sleep 3)
[handler] Handling a request... (sleep 4)
[handler] Handling a request... (sleep 5)
[handler] Throwing error

Neither server.events.on({ name: "request", channels: ["error"] }, fn) nor server.ext("onPreResponse", fn) callback functions are called if the incoming request gets prematurely closed. However, if we increase the request timeout, e.g., AbortSignal.timeout(10_000), both callback functions will get called.

What result did you expect?

I'm not sure if the shown hapi behavior is a bug or if it works as intended, especially because the onPreResponse documentation mentions that it is “always called, unless the request is aborted.” Nevertheless, it's evident that there is existing error-tracking software that seems to be expecting to capture all errors using the approach. The fact that some errors are not getting captured is an issue. I would like to start a discussion to figure out a way forward on how to improve error tracking around aborted requests.

主要语言
JavaScript
星标
14.8k
派生
1.4k
平均合并
12 分钟
30 天内合并 PR
6

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

hapijs/hapi 的其他 Issue

查看 hapijs/hapi 的全部 Issue

相似的 Issue

更多 JavaScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。