Effect.retry 怎么重试才不算盲目重试?
task.pipe(Effect.retry(Schedule.recurs(5))) 看起来很稳妥:失败了,再试五次。但这段代码对任何错误都重试,没有间隔,也不区分错误。
重试之前先对错误分类,只重试瞬时错误,配上指数退避和次数上限,并且确认被重试的操作重复执行是安全的。
重试是一个策略问题,不是「多试几次」。Schedule 描述重试的节奏,Effect.retry 负责套用它。完整的讲法见 时间与重试 和 重试与 Schedule。
盲目重试会出什么问题?
task.pipe(Effect.retry(Schedule.recurs(5)))这段代码会对任何错误重试五次,没有间隔,也不区分错误。对「参数不合法」重试五次,只是五次同样的失败;对已经过载的服务立刻重试,只会让它更糟。
怎么只重试该重试的错误?
先分类,只重试瞬时错误,再配上退避和上限:
task.pipe(
Effect.retry({
schedule: Schedule.exponential("200 millis"),
times: 4,
while: (e) => e._tag === "Transient"
})
)Schedule.exponential("200 millis") 让间隔逐次拉长,times: 4 给出上限,while 只放行带 Transient 标签的错误。这里能按 _tag 判断,前提是你的错误是带标签的、而且已经分过类,错误分类的做法见 错误设计。
什么样的操作可以安全重试?
重试对象还要幂等。重试一个「扣款」操作之前,先确认它重复执行是安全的,否则重试本身就会造成伤害。
版本是 effect 4.0.5。本文的代码和结论都是示意,没有逐条运行验证;Transient 标签是示例中假设的错误分类,需要你自己定义。