Design and Usage of a Lightweight Go Retry Library
This article introduces a lightweight Go library named Retry that provides functional‑programming‑style retry mechanisms, explains the pain points of manual loop retries, describes its architecture, backoff algorithms, configuration options, and demonstrates both singleton and factory usage with complete code examples.
In daily development, developers often write repetitive loop‑based retry logic for remote service calls, which quickly becomes hard to maintain. The author, a veteran with 17 years in IT, presents a Go library called Retry that abstracts this pattern into a clean, functional‑programming interface.
The library addresses several pain points: duplicated for loops, fixed retry counts and intervals, low reusability, and difficulty handling non‑error return types. It offers a unified API to configure retry attempts, backoff strategies, jitter, and custom retry conditions.
Architecture : Retry is built around a configurable Config struct and supports two usage modes—singleton and factory. The singleton mode exposes simple functions Do and DoWithDefault , while the factory mode creates a Retry object via New and executes functions with TryOnConflict .
Backoff module : The library implements three backoff strategies— FixBackOff (fixed delay), RandomBackOff (random delay), and ExponentialBackOff (exponential delay). These can be combined using CombineBackOffs to produce flexible retry intervals. The delay calculation follows the formula: backoff = backoffFunc(factor * count + jitter * rand.Float64()) * 100 * Millisecond + delay where factor , jitter , count , and delay are configurable via WithFactor , WithJitter , WithInitDelay , etc.
Configuration options include WithCallback , WithContext , WithAttempts , WithAttemptsByError , WithFactor , WithInitDelay , WithJitter , WithRetryIfFunc , WithBackOffFunc , and WithDetail . These allow fine‑grained control over retry behavior and error handling.
Result handling : After execution, a Result struct is returned, containing fields such as count , data , tryError , and execErrors . Helper methods like Count() , Data() , TryError() , ExecErrors() , LastExecError() , and IsSuccess() simplify result inspection.
Code examples :
Singleton mode example:
package main
import (
"fmt"
"github.com/shengyanli1982/retry"
)
// retryable function
func testFunc() (any, error) {
return "lee", nil
}
func main() {
// retry call
result := retry.DoWithDefault(testFunc)
// result
fmt.Println("result:", result.Data())
fmt.Println("tryError:", result.TryError())
fmt.Println("execErrors:", result.ExecErrors())
fmt.Println("isSuccess:", result.IsSuccess())
}Factory mode example:
package main
import (
"errors"
"fmt"
"github.com/shengyanli1982/retry"
)
// retryable functions
func testFunc1() (any, error) {
return "testFunc1", nil
}
func testFunc2() (any, error) {
return nil, errors.New("testFunc2")
}
func main() {
// retry with config
r := retry.New(nil)
// try on conflict for testFunc1
result := r.TryOnConflict(testFunc1)
fmt.Println("========= testFunc1 =========")
fmt.Println("result:", result.Data())
fmt.Println("tryError:", result.TryError())
fmt.Println("execErrors:", result.ExecErrors())
fmt.Println("isSuccess:", result.IsSuccess())
// try on conflict for testFunc2
result = r.TryOnConflict(testFunc2)
fmt.Println("========= testFunc2 =========")
fmt.Println("result:", result.Data())
fmt.Println("tryError:", result.TryError())
fmt.Println("execErrors:", result.ExecErrors())
fmt.Println("isSuccess:", result.IsSuccess())
}Both examples show how the library abstracts retry logic, reduces boilerplate, and provides detailed error information when needed.
Conclusion : Retry is a lightweight, easy‑to‑use Go library that standardizes retry operations through functional programming patterns. Its dual modes, flexible backoff strategies, and comprehensive configuration make it suitable for most backend retry scenarios, improving code readability and maintainability.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.