Effect 的 HTTP 服务端报错会自动上报吗?

你在每个 handler 里手写 withErrorReporting 之前,先看一眼边界:服务端那一层其实已经替你接好了。

会:Effect 的 HTTP 服务端边界会把失败 cause 交给 ErrorReporter,不用在每个 handler 里手写;但 reporter layer 必须与路由一起出现在最终装配的 layer 里,用 Layer.provide 喂给路由时一条都收不到。

ErrorReporter 是 Effect 4 里集中上报错误的模块(整体见 Effect 里怎么统一上报错误?,它在 4.0.5 里是 unstable)。官方 JSDoc 写明 HTTP 与 RPC 服务端模块会触发上报。我实际验证了 HTTP 这一侧,下面是怎么验证的,以及结论。

怎么验证 HTTP 边界会上报?

import { Effect, ErrorReporter, Layer } from "effect"
import { HttpRouter, HttpServerResponse } from "effect/http"

const seen: Array<string> = []
const reporter = ErrorReporter.make(({ error, severity }) => {
  seen.push(`${severity} ${error.message}`)
})
const Reporters = ErrorReporter.layer([reporter])

const Routes = Layer.mergeAll(
  HttpRouter.add("GET", "/ok", Effect.succeed(HttpServerResponse.text("ok"))),
  HttpRouter.add("GET", "/boom", Effect.die(new Error("db exploded")))
)

const probe = async (label: string, app: Layer.Layer<never, never, HttpRouter.HttpRouter>) => {
  const { handler, dispose } = HttpRouter.toWebHandler(app)
  for (const path of ["/ok", "/boom", "/missing"]) {
    seen.length = 0
    const res = await handler(new Request(`http://localhost${path}`))
    console.log(label, path, res.status, seen)
  }
  await dispose()
}

// 与路由并列合并:请求纤程能读到 reporter
await probe("merge", Layer.merge(Routes, Reporters))
// 用 provide 喂给路由:reporter 没有进入请求纤程
await probe("provide", Routes.pipe(Layer.provide(Reporters)))

哪些响应会上报,哪些不会?

/ok 不上报;/boom 返回 500,同时上报一条 Info db exploded;/missing 返回 404,不上报。

404 不上报是因为路由未命中的错误自带 ignore 标注,我在源码里看到它,行为也跑出来了。/boom 是 Info 而不是更高的级别,是 ErrorReporter 的默认 severity,见 ErrorReporter 里 defect 为什么也是 Info?。

effect/http-api 里内置的 HttpApiError.NotFound、BadRequest、Unauthorized、Forbidden、Conflict 等在源码里都标了 ignore,而 InternalServerError 没有。我用 ErrorReporter.isIgnored 实际检查了 NotFound 和 InternalServerError,结果分别是 true 和 false,其余几个只读了源码。这就是官方给的示范:预期的 4xx 不上报,真正的服务端错误才上报。

为什么用 provide 喂给路由就收不到?

同一个 reporter layer,用 Layer.merge 和路由并列时能收到上报,用 Layer.provide 喂给路由时却一条都没有。我没有深挖内部机制,只确认了这个现象:reporter 需要出现在 HTTP 服务最终装配的 layer 输出里。

排查「上报没生效」时先看这里。两种组合方式在依赖传递上的区别,可以参考 Effect 的 provide 和 provideMerge 有什么区别?。

RPC 服务端也一样吗?

源码里 RPC 服务端同样走了内部的 reportCauseUnsafe,在一次响应失败、响应编码失败时触发。但我没有写 RPC 的运行验证,这一点只是读源码得出的,请当作未验证。

版本是 effect 4.0.5。HTTP 一侧的 /ok、/boom、/missing 行为,以及 merge 与 provide 两种装配的差异,在这个版本上跑过;HttpApiError.NotFound 与 InternalServerError 的 isIgnored 结果检查过,其余内置错误是否标 ignore 只读了源码。RPC 服务端上报没有运行验证。merge 与 provide 差异的内部原因没有深挖。