@@ -8,25 +8,27 @@ slightly inspired by [Try::Tiny::Retry](https://metacpan.org/pod/Try::Tiny::Retr
88http get with retry:
99
1010 url := "http://example.com"
11- var body []byte
1211
13- err := retry.Do (
14- func() error {
12+ body, err := retry.DoWithData (
13+ func() ([]byte, error) {
1514 resp, err := http.Get(url)
1615 if err != nil {
17- return err
16+ return nil, err
1817 }
1918 defer resp.Body.Close()
20- body, err = ioutil.ReadAll(resp.Body)
19+ body, err : = ioutil.ReadAll(resp.Body)
2120 if err != nil {
22- return err
21+ return nil, err
2322 }
2423
25- return nil
24+ return body, nil
2625 },
2726 )
27+ if err != nil {
28+ // handle error
29+ }
2830
29- fmt.Println(body)
31+ fmt.Println(string( body) )
3032
3133[next examples](https://github.com/avast/retry-go/tree/master/examples)
3234
@@ -72,6 +74,8 @@ import (
7274// Function signature of retryable function
7375type RetryableFunc func () error
7476
77+ type RetryableFuncWithData [T any ] func () (T , error )
78+
7579// Default timer is a wrapper around time.After
7680type timerImpl struct {}
7781
@@ -80,7 +84,18 @@ func (t *timerImpl) After(d time.Duration) <-chan time.Time {
8084}
8185
8286func Do (retryableFunc RetryableFunc , opts ... Option ) error {
87+ retryableFuncWithData := func () (any , error ) {
88+ err := retryableFunc ()
89+ return nil , err
90+ }
91+
92+ _ , err := DoWithData (retryableFuncWithData , opts ... )
93+ return err
94+ }
95+
96+ func DoWithData [T any ](retryableFunc RetryableFuncWithData [T ], opts ... Option ) (T , error ) {
8397 var n uint
98+ var emptyT T
8499
85100 // default
86101 config := newDefaultRetryConfig ()
@@ -91,27 +106,30 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
91106 }
92107
93108 if err := config .context .Err (); err != nil {
94- return err
109+ return emptyT , err
95110 }
96111
97112 // Setting attempts to 0 means we'll retry until we succeed
98113 if config .attempts == 0 {
99- for err := retryableFunc (); err != nil ; err = retryableFunc () {
114+ for {
115+ t , err := retryableFunc ()
116+ if err == nil {
117+ return t , nil
118+ }
119+
100120 n ++
101121
102122 if ! IsRecoverable (err ) {
103- return err
123+ return emptyT , err
104124 }
105125
106126 config .onRetry (n , err )
107127 select {
108128 case <- config .timer .After (delay (config , n , err )):
109129 case <- config .context .Done ():
110- return config .context .Err ()
130+ return emptyT , config .context .Err ()
111131 }
112132 }
113-
114- return nil
115133 }
116134
117135 var errorLog Error
@@ -129,7 +147,7 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
129147 lastErrIndex := n
130148 shouldRetry := true
131149 for shouldRetry {
132- err := retryableFunc ()
150+ t , err := retryableFunc ()
133151
134152 if err != nil {
135153 errorLog [lastErrIndex ] = unpackUnrecoverable (err )
@@ -157,15 +175,15 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
157175 case <- config .timer .After (delay (config , n , err )):
158176 case <- config .context .Done ():
159177 if config .lastErrorOnly {
160- return config .context .Err ()
178+ return emptyT , config .context .Err ()
161179 }
162180 n ++
163181 errorLog [n ] = config .context .Err ()
164- return errorLog [:lenWithoutNil (errorLog )]
182+ return emptyT , errorLog [:lenWithoutNil (errorLog )]
165183 }
166184
167185 } else {
168- return nil
186+ return t , nil
169187 }
170188
171189 n ++
@@ -177,9 +195,9 @@ func Do(retryableFunc RetryableFunc, opts ...Option) error {
177195 }
178196
179197 if config .lastErrorOnly {
180- return errorLog [lastErrIndex ]
198+ return emptyT , errorLog [lastErrIndex ]
181199 }
182- return errorLog [:lenWithoutNil (errorLog )]
200+ return emptyT , errorLog [:lenWithoutNil (errorLog )]
183201}
184202
185203func newDefaultRetryConfig () * Config {
0 commit comments