Skip to content

Commit

Permalink
GODRIVER-1962 unwrap errors in WithTransaction (#634)
Browse files Browse the repository at this point in the history
  • Loading branch information
iwysiu committed Apr 23, 2021
1 parent 88fed5b commit 54c8ba3
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 7 deletions.
11 changes: 8 additions & 3 deletions mongo/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,21 @@ func unwrap(err error) error {
return u.Unwrap()
}

// IsNetworkError returns true if err is a network error
func IsNetworkError(err error) bool {
// errorHasLabel returns true if err contains the specified label
func errorHasLabel(err error, label string) bool {
for ; err != nil; err = unwrap(err) {
if e, ok := err.(ServerError); ok {
return e.HasErrorLabel("NetworkError")
return e.HasErrorLabel(label)
}
}
return false
}

// IsNetworkError returns true if err is a network error
func IsNetworkError(err error) bool {
return errorHasLabel(err, "NetworkError")
}

// MongocryptError represents an libmongocrypt error during client-side encryption.
type MongocryptError struct {
Code int32
Expand Down
6 changes: 2 additions & 4 deletions mongo/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,8 @@ func (s *sessionImpl) WithTransaction(ctx context.Context, fn func(sessCtx Sessi
default:
}

if cerr, ok := err.(CommandError); ok {
if cerr.HasErrorLabel(driver.TransientTransactionError) {
continue
}
if errorHasLabel(err, driver.TransientTransactionError) {
continue
}
return res, err
}
Expand Down
36 changes: 36 additions & 0 deletions mongo/with_transactions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ var (
withTxnFailedEvents []*event.CommandFailedEvent
)

type wrappedError struct {
err error
}

func (we wrappedError) Error() string {
return we.err.Error()
}

func (we wrappedError) Unwrap() error {
return we.err
}

func TestConvenientTransactions(t *testing.T) {
client := setupConvenientTransactions(t)
db := client.Database("TestConvenientTransactions")
Expand Down Expand Up @@ -381,6 +393,30 @@ func TestConvenientTransactions(t *testing.T) {
// Assert that transaction is canceled within 500ms and not 2 seconds.
assert.Soon(t, callback, 500*time.Millisecond)
})
t.Run("wrapped transient transaction error retried", func(t *testing.T) {
sess, err := client.StartSession()
assert.Nil(t, err, "StartSession error: %v", err)
defer sess.EndSession(context.Background())

// returnError tracks whether or not the callback is being retried
returnError := true
res, err := sess.WithTransaction(context.Background(), func(sessCtx SessionContext) (interface{}, error) {
if returnError {
returnError = false
return nil, wrappedError{
CommandError{
Name: "test Error",
Labels: []string{driver.TransientTransactionError},
},
}
}
return false, nil
})
assert.Nil(t, err, "WithTransaction error: %v", err)
resBool, ok := res.(bool)
assert.True(t, ok, "expected result type %T, got %T", false, res)
assert.False(t, resBool, "expected result false, got %v", resBool)
})
}

func setupConvenientTransactions(t *testing.T, extraClientOpts ...*options.ClientOptions) *Client {
Expand Down

0 comments on commit 54c8ba3

Please sign in to comment.