Retry wraps a BlockingAsyncOp with a retry policy. It will retry the operation if it returns a types.Err that wraps a RetryableError returning true for IsRetryable.
(fn functions.BlockingAsyncOp, opts ...RetryOption)
| 172 | // Retry wraps a BlockingAsyncOp with a retry policy. |
| 173 | // It will retry the operation if it returns a types.Err that wraps a RetryableError returning true for IsRetryable. |
| 174 | func Retry(fn functions.BlockingAsyncOp, opts ...RetryOption) functions.BlockingAsyncOp { |
| 175 | config := &retryConfig{ |
| 176 | maxAttempts: 3, |
| 177 | backoff: 100 * time.Millisecond, |
| 178 | } |
| 179 | for _, opt := range opts { |
| 180 | opt(config) |
| 181 | } |
| 182 | |
| 183 | return func(ctx context.Context, args ...ref.Val) ref.Val { |
| 184 | var lastErr ref.Val |
| 185 | var backoff *time.Timer |
| 186 | defer func() { |
| 187 | if backoff != nil { |
| 188 | backoff.Stop() |
| 189 | } |
| 190 | }() |
| 191 | for i := 0; i < config.maxAttempts; i++ { |
| 192 | if i > 0 { |
| 193 | // Reuse a single timer across attempts and stop it on cancellation so the |
| 194 | // pending timer is not left to fire after the call returns. |
| 195 | if backoff == nil { |
| 196 | backoff = time.NewTimer(config.backoff) |
| 197 | } else { |
| 198 | backoff.Reset(config.backoff) |
| 199 | } |
| 200 | select { |
| 201 | case <-backoff.C: |
| 202 | case <-ctx.Done(): |
| 203 | backoff.Stop() |
| 204 | return types.NewErr("operation cancelled during retry: %v", ctx.Err()) |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | res := fn(ctx, args...) |
| 209 | if !types.IsError(res) { |
| 210 | return res |
| 211 | } |
| 212 | |
| 213 | err := res.(*types.Err) |
| 214 | lastErr = res |
| 215 | |
| 216 | if !isRetryable(err) { |
| 217 | return res |
| 218 | } |
| 219 | } |
| 220 | return lastErr |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | // RetryBinding wraps a BlockingAsyncOp with a retry policy and returns an OverloadOpt. |
| 225 | func RetryBinding(fn functions.BlockingAsyncOp, opts ...RetryOption) decls.OverloadOpt { |
no test coverage detected