Effect 怎么只重试特定的错误?
对一个参数校验失败的请求重试三次,结果只有一个:多等几秒,然后得到同一个错误。
答案是:在 Effect.retry 里用 while(或 until)对失败的 E 做判断,只放行「再试一次可能不同」的错误。 判断发生在错误类型上,所以前提是你的错误是带 _tag 的类型,而不是一团字符串。
下面讲为什么要筛、while 怎么写,以及两个边界:缺陷和中断不会被重试,非幂等操作要先想幂等。没有重试策略的读者,可以先看 Effect 里怎么给偶发失败的调用加重试;错误类型怎么设计,见 Effect 的错误类型。
为什么不能对所有错误重试?
重试只对瞬时的失败有意义:网络抖动、限流、下游暂时不可用。对「输入不合法」「资源不存在」「没有权限」重试,只会放大延迟和下游压力。不看错误类型的重试,是在掩盖 bug。
while 条件怎么写?
import { Effect, Schedule } from "effect"
type FetchError =
| { readonly _tag: "NetworkError" }
| { readonly _tag: "RateLimited" }
| { readonly _tag: "NotFound" }
declare const fetchUser: Effect.Effect<string, FetchError>
export const selective = fetchUser.pipe(
Effect.retry({
while: (e) => e._tag === "NetworkError" || e._tag === "RateLimited",
schedule: Schedule.max([Schedule.exponential("200 millis"), Schedule.recurs(4)])
})
)NetworkError 和 RateLimited 会按 schedule 重试,NotFound 第一次就直接失败。
缺陷和中断会被重试吗?
不会。retry 只作用于类型里的失败。缺陷(defect)和中断不会被重试,这是 Effect 错误即类型 里区分 failure 与 defect 的直接收益:该修的 bug 不会被重试悄悄吞掉。
非幂等的操作能重试吗?
要谨慎。重试「扣款」之前,要先确认下游能用幂等键去重,否则重试可能造成重复扣款。这是业务设计问题,Schedule 不能替你解决。
本文以 effect v4 为准,原文没有标注具体版本号。while 的写法与缺陷、中断不被重试的描述是对 API 行为的说明,代码示例取自原章节,没有对真实服务运行;幂等键的建议是设计上的提醒,没有做过实验。