Skip to content

goioc/retro

Repository files navigation

goioc/retro: Handy retry-library

goioc

Go go.dev reference CodeFactor Go Report Card Quality Gate Status codecov DeepSource

ko-fi

Why another retry library?

There's a bunch of excellent retry-related Go libraries out there (and I took inspiration from some of them), like this one. Some of them are highly configurable (even more configurable than mine), but I was always lacking one feature: configurability by the error. I.e., most of the libraries allow you to configure the "retrier" in some or another way, making it behave the same way for all the "retriable" errors. What I needed for some of my usecases, is having different retry strategies for different errors. And that's why this library was made.

Basic usage

So, let's say we have a DB-related function that may return different types of errors: it returns sql.ErrNoRows if the result-set of the lookup is empty, and it returns driver.ErrBadConn if there's some trasient connectivity error. In the first case, I want to retry with the constant rate (let's say, every second) and the maximum retry count of 3. In the second case, I want to have an exponential back-off starting with 10 milliseconds, but the retry delay should not exceed 1 second. All together, I want the retry phase to not exceed 5 seconds. Here's how one could implement it using the retro library:

	caller := NewCaller(). // instantiating the "retrier" aka "caller"
		WithRetriableError(sql.ErrNoRows,
			NewBackoffStrategy(NewConstant(1), time.Second).
				WithMaxRetries(3)). // constant back-off at the rate of 1 second and 3 max retries for sql.ErrNoRows
		WithRetriableError(driver.ErrBadConn,
			NewBackoffStrategy(NewExponential(2), time.Millisecond).
				WithCappedDuration(time.Second)). // exponential back-off with factor 2, 1 millisecond time unit and max retry delay of 1 second
		WithMaxDuration(5 * time.Second) // maximum retry duration (across all retriable errors) - 5 seconds
	if err := caller.Call(context.TODO(), func() error {
		return queryDBFunction(...) // your function that runs a database query
	}); err != nil {
		panic(err)
	}

You can also specify a retry startegy for any erro using WithRetryOnAnyError(...) on the caller.

More examples?

Please, take a look at the unit-tests for more examples.