Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hyp3rd/go-again
`go-again` is an high-performance and thread-safe retry library with fine-grained access to the configuration options.
https://github.com/hyp3rd/go-again
go retry retry-fuctions retry-library retryer
Last synced: 11 days ago
JSON representation
`go-again` is an high-performance and thread-safe retry library with fine-grained access to the configuration options.
- Host: GitHub
- URL: https://github.com/hyp3rd/go-again
- Owner: hyp3rd
- License: mpl-2.0
- Created: 2023-01-17T21:54:08.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-03-02T16:14:03.000Z (10 months ago)
- Last Synced: 2024-06-19T23:14:18.769Z (6 months ago)
- Topics: go, retry, retry-fuctions, retry-library, retryer
- Language: Go
- Homepage:
- Size: 57.6 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# go-again
[![Go](https://github.com/hyp3rd/go-again/actions/workflows/go.yml/badge.svg)][build-link] [![CodeQL](https://github.com/hyp3rd/go-again/actions/workflows/codeql.yml/badge.svg)][codeql-link]
[![Codacy Security Scan](https://github.com/hyp3rd/go-again/actions/workflows/codacy.yml/badge.svg)][codacy-security-scan-link]`go-again` **thread safely** wraps a given function and executes it until it returns a nil error or exceeds the maximum number of retries.
The configuration consists of the maximum number of retries, the interval, a jitter to add a randomized backoff, the timeout, and a registry to store errors that you consider temporary, hence worth a retry.The `Do` method takes a context, a function, and an optional list of `temporary errors` as arguments. It supports cancellation from the context and a channel invoking the `Cancel()` function.
The returned type is `Errors` which contains the list of errors returned at each attempt and the last error returned by the function.```golang
// Errors holds the error returned by the retry function along with the trace of each attempt.
type Errors struct {
// Retries hold the trace of each attempt.
Retries map[int]error
// Last holds the last error returned by the retry function.
Last error
}
```The registry only allows you to retry a function if it returns a registered error:
```go
// Init with defaults.
retrier, err := again.NewRetrier()
if err != nil {
// handle error
}
retrier.Registry.RegisterTemporaryError("http.ErrAbortHandler", func() TemporaryError {
return http.ErrAbortHandler
})defer retrier.Registry.UnRegisterTemporaryError("http.ErrAbortHandler")
var retryCount int
errs := retrier.Do(context.TODO(), func() error {
retryCount++
if retryCount < 3 {
return http.ErrAbortHandler
}
return nil
}, "http.ErrAbortHandler")if errs.Last != nil {
// handle error
}
```Should you retry regardless of the error returned, that's easy. It's enough calling the Do function without passing a plausible set of registered error names:
```go
var retryCount int
retrier, err := again.NewRetrier(again.WithTimeout(1*time.Second),
again.WithJitter(500*time.Millisecond),
again.WithMaxRetries(3))if err != nil {
// handle error
}
errs := retrier.Do(context.TODO(), func() error {
retryCount++
if retryCount < 3 {
return http.ErrAbortHandler
}
return nil
})
if errs.Last != nil {
// handle error
}
```It's also possible to create a Registry with the [**temporary default errors**](./registry.go?plain=1#L26):
`retrier.Registry.LoadDefaults()`.
You can extend the list with your errors by calling the `RegisterTemporaryError` method.**Walk through the [documentation](https://pkg.go.dev/github.com/hyp3rd/[email protected]#section-documentation) for further details about the settings, the programmability, the implementation.**
## Performance
A retrier certainly adds overhead to the execution of a function. `go-again` is designed to produce a minimal impact on the performance of your code, keeping thread safety and flexibility. The following benchmark shows the overhead of a retrier with 5 retries, 1s interval, 10ms jitter, and 1s timeout:
```bash
go test -bench=. -benchmem -benchtime=4s . -timeout 30m
goos: darwin
goarch: amd64
pkg: github.com/hyp3rd/go-again
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkRetry-16 490851 8926 ns/op 5376 B/op 1 allocs/op
PASS
ok github.com/hyp3rd/go-again 40.390s
```## Installation
```bash
go get github.com/hyp3rd/go-again
```## Usage
For examples with cancellation, see [**examples**](./examples). To run the examples you can leverage the `Makefile`:
```bash
make run example=chan
make run example=context
```### Retrier
```go
package mainimport (
"fmt"
"time""github.com/hyp3rd/go-again"
)func main() {
// Create a new retrier.
retrier, err := again.NewRetrier(again.WithTimeout(1*time.Second),
again.WithJitter(500*time.Millisecond),
again.WithMaxRetries(3))if err != nil {
// handle error
}// Register a temporary error.
retrier.Registry.RegisterTemporaryError("temporary error", func() again.TemporaryError {
return fmt.Errorf("temporary error")
})// Retry a function.
errs := retrier.Do(context.TODO(), func() error {
// Do something here.
return fmt.Errorf("temporary error")
}, "temporary error")
if errs.Last != nil {
fmt.Println(err)
}
}
```## License
The code and documentation in this project are released under Mozilla Public License 2.0.
## Author
I'm a surfer, a crypto trader, and a software architect with 15 years of experience designing highly available distributed production environments and developing cloud-native apps in public and private clouds. Feel free to hook me up on [LinkedIn](https://www.linkedin.com/in/francesco-cosentino/).
[build-link]: https://github.com/hyp3rd/go-again/actions/workflows/go.yml
[codeql-link]:https://github.com/hyp3rd/go-again/actions/workflows/codeql.yml
[codacy-security-scan-link]:https://github.com/hyp3rd/go-again/actions/workflows/codacy.yml