mcpField
E
effect-errors-retries

effect-errors-retries

github.com/mepuka开发542 次安装44 周前更新
代码仓库

关于 effect-errors-retries

面向 Effect 开发者的编码技能,介绍结构化错误、恢复、重试和超时的实现方式。它还建议在使用 API 前查阅本地 Effect 源码与测试。

主要功能

  1. 01带标签的领域错误模式
  2. 02在边界映射基础设施错误
  3. 03使用 catchTags 恢复
  4. 04通过退避与抖动重试
  5. 05用超时限制延迟
  6. 06查阅本地 Effect 源码

适用场景

  1. 01定义领域专属的失败类型
  2. 02转换 HTTP 或数据库错误
  3. 03重试暂时性故障
  4. 04限制操作持续时间

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mepuka/effect-ontology --skill effect-errors-retries

安装后在 Claude Code 中输入/effect-errors-retries确认已加载。

详细介绍

错误与重试

适用场景

  • 定义领域错误和恢复策略
  • 需要将基础设施错误映射到领域边界
  • 必须添加重试、退避、抖动和超时

错误建模

import { Data } from "effect"

class ValidationError extends Data.TaggedError("ValidationError")<{ field: string; reason: string }>{}
class NotFoundError extends Data.TaggedError("NotFoundError")<{ id: string }>{}

映射/边界

const repoCall = Effect.fail(new ValidationError({ field: "name", reason: "empty" }))

const service = repoCall.pipe(
  Effect.mapError((e) => new ServiceError({ cause: e }))
)

精确恢复

program.pipe(
  Effect.catchTags({
    ValidationError: (e) => Effect.succeed(fix(e)),
    NotFoundError: (e) => Effect.succeed(defaultValue)
  })
)

重试策略

import { Schedule } from "effect"

const retry = Schedule.exponential("100 millis").pipe(
  Schedule.jittered,
  Schedule.compose(Schedule.recurs(5))
)

const resilient = program.pipe(Effect.retry(retry))

超时与竞态

const withTimeout = Effect.timeout(program, "2 seconds")

指南与注意事项

  • 为每种失败模式创建独立的 TaggedError 类型;避免使用通用 Error
  • 在边界处将底层(HTTP/DB)错误映射为领域错误
  • 只重试暂时性错误(使用 Schedule.whileInput 谓词)
  • 始终将重试与超时结合,以限制延迟
  • 为了清晰和安全,优先使用 catchTags 而非宽泛的 catchAll

实际示例:映射 HTTP 错误并有选择地重试

// Verify URL with HEAD-range request, map ResponseError to domain errors,
// retry with exponential backoff unless invalid.
const verify = http.get(url, { headers: { range: "bytes=0-0" } }).pipe(
  Effect.flatMap(HttpClientResponse.filterStatus((s) => s < 400)),
  Effect.catchIf(
    (e) => e._tag === "ResponseError",
    (cause) =>
      cause.response.status < 500
        ? Effect.fail(new VideoInvalidError({ cause: "NotFound" }))
        : Effect.fail(new ExternalLoomError({ cause: cause.response }))
  ),
  Effect.retry({
    schedule: Schedule.exponential("200 millis"),
    times: 3,
    while: (e) => e._tag !== "VideoInvalidError"
  }),
  Effect.catchTag("RequestError", Effect.die)
)

实际示例:从 Cause 中捕获结构化错误

import { Cause } from "effect"

const captureErrors = (cause: Cause.Cause<unknown>) => Effect.gen(function* () {
  if (Cause.isInterruptedOnly(cause)) return { interrupted: true, errors: [] }
  const raw = captureErrorsFrom(cause)
  const errors = yield* Effect.forEach(raw, transformRawError({ stripCwd: true }))
  return { interrupted: false, errors }
})

快速判断

  • 领域错误 → 每种类型对应一个 TaggedError
  • 在边界处将底层错误映射为高层错误
  • 只重试暂时性错误;使用 Schedule.whileInput 设置谓词

交叉链接

本地源码参考

重要:实现前先搜索本地 Effect 源码

完整的 Effect 源代码位于 docs/effect-source/。编写 Effect 代码前,务必搜索实际实现。

关键源文件
  • Effect:docs/effect-source/effect/src/Effect.ts
  • Data:docs/effect-source/effect/src/Data.ts
  • Schedule:docs/effect-source/effect/src/Schedule.ts
  • Cause:docs/effect-source/effect/src/Cause.ts
搜索示例
# Find error handling patterns
grep -F "catchTag" docs/effect-source/effect/src/Effect.ts
grep -F "catchAll" docs/effect-source/effect/src/Effect.ts
grep -F "mapError" docs/effect-source/effect/src/Effect.ts

# Study TaggedError
grep -F "TaggedError" docs/effect-source/effect/src/Data.ts

# Find retry and schedule patterns
grep -F "retry" docs/effect-source/effect/src/Schedule.ts
grep -F "exponential" docs/effect-source/effect/src/Schedule.ts
grep -F "jittered" docs/effect-source/effect/src/Schedule.ts

# Study Cause operations
grep -F "isInterruptedOnly" docs/effect-source/effect/src/Cause.ts
工作流
  1. 确定所需的错误处理 API(例如,catchTag、retry)
  2. 在 docs/effect-source/effect/src/Effect.ts 中搜索其实现
  3. 研究类型和错误恢复模式
  4. 查看测试文件中的用法示例
  5. 根据实际实现编写代码

实际源码 > 文档 > 假设

参考资料

评论

支持 Markdown