@@ -25,8 +25,36 @@ http get with retry:
2525 return nil
2626 },
2727 )
28+ if err != nil {
29+ // handle error
30+ }
31+
32+ fmt.Println(string(body))
33+
34+ http get with retry with data:
35+
36+ url := "http://example.com"
37+
38+ body, err := retry.DoWithData(
39+ func() ([]byte, error) {
40+ resp, err := http.Get(url)
41+ if err != nil {
42+ return nil, err
43+ }
44+ defer resp.Body.Close()
45+ body, err := ioutil.ReadAll(resp.Body)
46+ if err != nil {
47+ return nil, err
48+ }
49+
50+ return body, nil
51+ },
52+ )
53+ if err != nil {
54+ // handle error
55+ }
2856
29- fmt.Println(body)
57+ fmt.Println(string( body) )
3058
3159[next examples](https://github.com/avast/retry-go/tree/master/examples)
3260
@@ -72,6 +100,9 @@ import (
72100// Function signature of retryable function
73101type RetryableFunc func () error
74102
103+ // Function signature of retryable function with data
104+ type RetryableFuncWithData [T any ] func () (T , error )
105+
75106// Default timer is a wrapper around time.After
76107type timerImpl struct {}
77108
@@ -80,7 +111,17 @@ func (t *timerImpl) After(d time.Duration) <-chan time.Time {
80111}
81112
82113func Do (retryableFunc RetryableFunc , opts ... Option ) error {
114+ retryableFuncWithData := func () (any , error ) {
115+ return nil , retryableFunc ()
116+ }
117+
118+ _ , err := DoWithData (retryableFuncWithData , opts ... )
119+ return err
120+ }
121+
122+ func DoWithData [T any ](retryableFunc RetryableFuncWithData [T ], opts ... Option ) (T , error ) {
83123 var n uint
124+ var emptyT T
84125
85126 // default
86127 config := newDefaultRetryConfig ()
@@ -91,30 +132,33 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
91132 }
92133
93134 if err := config .context .Err (); err != nil {
94- return err
135+ return emptyT , err
95136 }
96137
97138 // Setting attempts to 0 means we'll retry until we succeed
98139 if config .attempts == 0 {
99- for err := retryableFunc (); err != nil ; err = retryableFunc () {
140+ for {
141+ t , err := retryableFunc ()
142+ if err == nil {
143+ return t , nil
144+ }
145+
100146 if ! IsRecoverable (err ) {
101- return err
147+ return emptyT , err
102148 }
103149
104150 if ! config .retryIf (err ) {
105- return err
151+ return emptyT , err
106152 }
107153
108154 n ++
109155 config .onRetry (n , err )
110156 select {
111157 case <- config .timer .After (delay (config , n , err )):
112158 case <- config .context .Done ():
113- return config .context .Err ()
159+ return emptyT , config .context .Err ()
114160 }
115161 }
116-
117- return nil
118162 }
119163
120164 errorLog := Error {}
@@ -126,9 +170,9 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
126170
127171 shouldRetry := true
128172 for shouldRetry {
129- err := retryableFunc ()
173+ t , err := retryableFunc ()
130174 if err == nil {
131- return nil
175+ return t , nil
132176 }
133177
134178 errorLog = append (errorLog , unpackUnrecoverable (err ))
@@ -156,22 +200,20 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
156200 case <- config .timer .After (delay (config , n , err )):
157201 case <- config .context .Done ():
158202 if config .lastErrorOnly {
159- return config .context .Err ()
203+ return emptyT , config .context .Err ()
160204 }
161- n ++
162205
163- return append (errorLog , config .context .Err ())
206+ return emptyT , append (errorLog , config .context .Err ())
164207 }
165208
166209 n ++
167210 shouldRetry = shouldRetry && n < config .attempts
168211 }
169212
170213 if config .lastErrorOnly {
171- return errorLog .Unwrap ()
214+ return emptyT , errorLog .Unwrap ()
172215 }
173-
174- return errorLog
216+ return emptyT , errorLog
175217}
176218
177219func newDefaultRetryConfig () * Config {
0 commit comments