关于 effect-errors-retries
面向 Effect 开发者的编码技能,介绍结构化错误、恢复、重试和超时的实现方式。它还建议在使用 API 前查阅本地 Effect 源码与测试。
主要功能
- 01带标签的领域错误模式
- 02在边界映射基础设施错误
- 03使用 catchTags 恢复
- 04通过退避与抖动重试
- 05用超时限制延迟
- 06查阅本地 Effect 源码
适用场景
- 01定义领域专属的失败类型
- 02转换 HTTP 或数据库错误
- 03重试暂时性故障
- 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设置谓词
交叉链接
- 基础:操作符选择和
.pipe风格 - 并发:竞态和超时模式
- EffectPatterns 灵感来源:https://github.com/PaulJPhilp/EffectPatterns
本地源码参考
重要:实现前先搜索本地 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
工作流
- 确定所需的错误处理 API(例如,catchTag、retry)
- 在
docs/effect-source/effect/src/Effect.ts中搜索其实现 - 研究类型和错误恢复模式
- 查看测试文件中的用法示例
- 根据实际实现编写代码
实际源码 > 文档 > 假设
参考资料
- Agent Skills 概览:https://www.anthropic.com/news/skills
- Skills 指南:https://docs.claude.com/en/docs/claude-code/skills
评论
支持 Markdown