Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added functions that take an error and set the retryable flag #53

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ When using the the wrapping functionality (e.g. `Wrap`, `Augment`, `Propagate`),
of an error is preserved as expected. Importantly, it is also preserved when constructing a new error from
a causal error with `NewInternalWithCause`.

Wrap an error with `Retryable` or `NotRetryable` to set the retryability explicitly. This will
override the retryability derived from the error code.

```go
retryableErr := terrors.Retryable(terrors.Augment(err, "didn't work, let's try again", nil))
if terrors.IsRetryable(retryableErr) {
// retry the operation
}
```

## API

Full API documentation can be found on
Expand Down
22 changes: 22 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,28 @@ func IsRetryable(err error) bool {
return false
}

// Retryable converts the error to a terror if necessary, and marks it as retryable.
func Retryable(err error) error {
if err == nil {
return nil
}
// Using propagate ensures the error can be converted to a terror
terr := Propagate(err).(*Error)
terr.SetIsRetryable(true)
return terr
}

// NotRetryable converts the error to a terror if necessary, and marks it as not retryable.
func NotRetryable(err error) error {
if err == nil {
return nil
}
// Using propagate ensures the error can be converted to a terror
terr := Propagate(err).(*Error)
terr.SetIsRetryable(false)
return terr
}

// Augment adds context to an existing error.
// If the error given is not already a terror, a new terror is created.
func Augment(err error, context string, params map[string]string) error {
Expand Down
15 changes: 15 additions & 0 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,21 @@ func TestIsRetryable(t *testing.T) {
assert.False(t, IsRetryable(&testRetryableError{false}))
assert.True(t, IsRetryable(&testRetryableError{true}))
assert.True(t, IsRetryable(&testRetryableError{true}))

// Setting using convenience functions
assert.True(t, IsRetryable(Retryable(errors.New(""))))
assert.False(t, IsRetryable(NotRetryable(errors.New(""))))
assert.True(t, IsRetryable(Retryable(Augment(errors.New(""), "", nil))))
assert.False(t, IsRetryable(NotRetryable(Augment(errors.New(""), "", nil))))

// Overriding the default for error types using convenience functions
assert.True(t, IsRetryable(Retryable(BadRequest("", "", nil))))
assert.True(t, IsRetryable(Retryable(BadResponse("", "", nil))))
assert.True(t, IsRetryable(Retryable(NotFound("", "", nil))))
assert.True(t, IsRetryable(Retryable(PreconditionFailed("", "", nil))))
assert.True(t, IsRetryable(Retryable(NonRetryableInternalService("", "", nil))))
assert.False(t, IsRetryable(NotRetryable(InternalService("", "", nil))))
assert.False(t, IsRetryable(NotRetryable(RateLimited("", "", nil))))
}

type testRetryableError struct {
Expand Down
Loading