Dapr retry package中的 retry.go 文件的源码学习。
重试策略
多次重试之间的间隔策略,有两种:PolicyConstant 是固定值,PolicyExponential是指数增长。
重试配置
注意: 每个字段都标记了
mapstructure
,这是为了使用 mapstructure 进行解码。
默认配置为:
不带重试的默认配置:
解码配置
DecodeConfig() 方法将 go 结构体解析为 Config
:
DecodeConfigWithPrefix() 方法在将 go 结构体解析为 Config
之前,先去除前缀,并进行key和value的正常化:
DecodeString()方法解析重试策略:
重试退避时间的生成
NewBackOff() 方法 返回一个 BackOff
实例,可直接与NotifyRecover
或backoff.RetryNotify
一起使用。该实例不会因为上下文取消而停止。要支持取消(推荐),请使用NewBackOffWithContext
。 由于底层的回退实现并不总是线程安全的,所以每次使用RetryNotifyRecover
或backoff.RetryNotify
时都应该调用NewBackOff
或NewBackOffWithContext
。
NewBackOffWithContext() 方法返回一个BackOff实例,以便与RetryNotifyRecover
或backoff.RetryNotify
直接使用。如果提供的上下文被取消,则用于取消重试。
由于底层的回退实现并不总是线程安全的,NewBackOff
或NewBackOffWithContext
应该在每次使用RetryNotifyRecover
或backoff.RetryNotify
时被调用。
恢复通知
标准 backoff.RetryNotify
的用法:
如果出现问题,需要多次重试才恢复,会存在几个问题:
- Notify()方法会被调用多次
- 不好判断是否恢复:理论上"恢复"的概念是先有出错(一次或者连续多次出错),然后成功(出错之后的第一次不出错)
NotifyRecover() 方法是 backoff.RetryNotify
的封装器,它为之前操作失败但后来恢复的情况增加了另一个回调。这个包装器的主要目的是只在操作第一次失败时调用 “notify”,在最后成功时调用 “recovered”。这有助于将日志信息限制在操作者需要被提醒的事件上。
这里的NotifyRecover() 方法包装了 Operation()
和 Notify()
函数:
备注:感觉 notified 这个变量的取名不够清晰,它的语义不应该是"是否触发了通知",而是"是否发生了错误而一直没有恢复"。应该改为类似 errorNotRecoverd 之类的,语义更清晰一些。