-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathretry.go
More file actions
90 lines (76 loc) · 2.07 KB
/
retry.go
File metadata and controls
90 lines (76 loc) · 2.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package ewrap
import (
"errors"
"time"
)
// RetryInfo holds information about retry attempts.
type RetryInfo struct {
// MaxAttempts is the maximum number of retry attempts.
MaxAttempts int
// CurrentAttempt is the current retry attempt.
CurrentAttempt int
// Delay is the delay between retry attempts.
Delay time.Duration
// LastAttempt is the timestamp of the last retry attempt.
LastAttempt time.Time
// ShouldRetry is a function that determines if a retry should be attempted.
ShouldRetry func(error) bool
}
// RetryOption configures RetryInfo.
type RetryOption func(*RetryInfo)
// WithRetry adds retry information to the error.
func WithRetry(maxAttempts int, delay time.Duration, opts ...RetryOption) Option {
return func(err *Error) {
retryInfo := &RetryInfo{
MaxAttempts: maxAttempts,
Delay: delay,
LastAttempt: time.Now(),
ShouldRetry: defaultShouldRetry,
}
for _, opt := range opts {
opt(retryInfo)
}
err.mu.Lock()
err.metadata["retry_info"] = retryInfo
err.mu.Unlock()
}
}
// WithRetryShould sets a custom ShouldRetry function.
func WithRetryShould(fn func(error) bool) RetryOption {
return func(ri *RetryInfo) {
if fn != nil {
ri.ShouldRetry = fn
}
}
}
// defaultShouldRetry is the default retry decision function.
func defaultShouldRetry(err error) bool {
// Don't retry validation errors
var wrappedErr *Error
if errors.As(err, &wrappedErr) {
if ctx, ok := wrappedErr.metadata["error_context"].(*ErrorContext); ok {
return ctx.Type != ErrorTypeValidation
}
}
return true
}
// CanRetry checks if the error can be retried.
func (e *Error) CanRetry() bool {
e.mu.RLock()
defer e.mu.RUnlock()
retryInfo, ok := e.metadata["retry_info"].(*RetryInfo)
if !ok {
return false
}
return retryInfo.CurrentAttempt < retryInfo.MaxAttempts &&
retryInfo.ShouldRetry(e)
}
// IncrementRetry increments the retry counter.
func (e *Error) IncrementRetry() {
e.mu.Lock()
defer e.mu.Unlock()
if retryInfo, ok := e.metadata["retry_info"].(*RetryInfo); ok {
retryInfo.CurrentAttempt++
retryInfo.LastAttempt = time.Now()
}
}