Created
September 1, 2017 13:33
-
-
Save sascha-andres/d1f11fb9bc6abc4f07b4118839b29d7f to your computer and use it in GitHub Desktop.
Simple Golang Retry Function // https://upgear.io/blog/simple-golang-retry-function/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func init() { | |
rand.Seed(time.Now().UnixNano()) | |
} | |
func retry(attempts int, sleep time.Duration, f func() error) error { | |
if err := f(); err != nil { | |
if s, ok := err.(stop); ok { | |
// Return the original error for later checking | |
return s.error | |
} | |
if attempts--; attempts > 0 { | |
// Add some randomness to prevent creating a Thundering Herd | |
jitter := time.Duration(rand.Int63n(int64(sleep))) | |
sleep = sleep + jitter/2 | |
time.Sleep(sleep) | |
return retry(attempts, 2*sleep, f) | |
} | |
return err | |
} | |
return nil | |
} | |
type stop struct { | |
error | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DeleteThing attempts to delete a thing. It will try a maximum of three times. | |
func DeleteThing(id string) error { | |
// Build the request | |
req, err := http.NewRequest( | |
"DELETE", | |
fmt.Sprintf("https://unreliable-api/things/%s", id), | |
nil, | |
) | |
if err != nil { | |
return fmt.Errorf("unable to make request: %s", err) | |
} | |
// Execute the request | |
return retry(3, time.Second, func() error { | |
resp, err := http.DefaultClient.Do(req) | |
if err != nil { | |
// This error will result in a retry | |
return err | |
} | |
defer resp.Body.Close() | |
s := resp.StatusCode | |
switch { | |
case s >= 500: | |
// Retry | |
return fmt.Errorf("server error: %v", s) | |
case s >= 400: | |
// Don't retry, it was client's fault | |
return stop{fmt.Errorf("client error: %v", s)} | |
default: | |
// Happy | |
return nil | |
} | |
}) | |
} |
Stumbled on your comment @AlbertoWang randomly so I'll leave the comment here in case someone else needs it:
func retry(attempts int, sleep time.Duration, f func() (string, error)) (string, error) {
s, err := f()
if err != nil {
if s, ok := err.(stop); ok {
// Return the original error for later checking
return "", s.error
}
if attempts--; attempts > 0 {
// Add some randomness to prevent creating a Thundering Herd
jitter := time.Duration(rand.Int63n(int64(sleep)))
sleep = sleep + jitter/2
time.Sleep(sleep)
return retry(attempts, 2*sleep, f)
}
return "", err
}
return s, nil
}
Hopefully didn't miss any s
, but there you go, you can add any number of params you want, here only added s string
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how to retry a function if the function not only returns
error
but also returns other params?