-
Notifications
You must be signed in to change notification settings - Fork 905
GODRIVER-3361 Improve connection error message. #2027
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
Changes from all commits
1cbbbda
076f0df
9cefb59
c3a7110
482f746
64c75e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,11 +10,17 @@ import ( | |
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"net" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/description" | ||
) | ||
|
||
var _ error = ConnectionError{} | ||
|
||
// ConnectionError represents a connection error. | ||
type ConnectionError struct { | ||
ConnectionID string | ||
|
@@ -28,21 +34,28 @@ type ConnectionError struct { | |
|
||
// Error implements the error interface. | ||
func (e ConnectionError) Error() string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest adding a compile check for var _ error = ConnectionError{} |
||
message := e.message | ||
var messages []string | ||
if e.init { | ||
fullMsg := "error occurred during connection handshake" | ||
if message != "" { | ||
fullMsg = fmt.Sprintf("%s: %s", fullMsg, message) | ||
} | ||
message = fullMsg | ||
messages = append(messages, "error occurred during connection handshake") | ||
} | ||
if e.Wrapped != nil && message != "" { | ||
return fmt.Sprintf("connection(%s) %s: %s", e.ConnectionID, message, e.Wrapped.Error()) | ||
if e.message != "" { | ||
messages = append(messages, e.message) | ||
} | ||
if e.Wrapped != nil { | ||
return fmt.Sprintf("connection(%s) %s", e.ConnectionID, e.Wrapped.Error()) | ||
if errors.Is(e.Wrapped, io.EOF) { | ||
messages = append(messages, "connection closed unexpectedly by the other side") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should create integration tests that verify all three branches work as expected. For the addr := bootstrapConnections(t, 1, func(nc net.Conn) {
_ = nc.Close() // Close the connection "server-side" / "other-side"
})
p := newPool(
poolConfig{Address: address.Address(addr.String())},
)
defer p.close(context.Background())
err := p.ready()
require.NoError(t, err)
conn, err := p.checkOut(context.Background())
fmt.Println(err)
_, err = conn.readWireMessage(context.Background())
fmt.Println(err) // expect io.EOF The timeout branches would just require holding a server response > than the timeout. I know we already do this with |
||
} | ||
if errors.Is(e.Wrapped, os.ErrDeadlineExceeded) { | ||
messages = append(messages, "client timed out waiting for server response") | ||
} else if err, ok := e.Wrapped.(net.Error); ok && err.Timeout() { | ||
messages = append(messages, "client timed out waiting for server response") | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the transformNetworkError function will wrap the error with context.DeadlineExceeded. Should we include that case here for safety? |
||
messages = append(messages, e.Wrapped.Error()) | ||
} | ||
if len(messages) > 0 { | ||
return fmt.Sprintf("connection(%s) %s", e.ConnectionID, strings.Join(messages, ": ")) | ||
} | ||
return fmt.Sprintf("connection(%s) %s", e.ConnectionID, message) | ||
return fmt.Sprintf("connection(%s)", e.ConnectionID) | ||
} | ||
|
||
// Unwrap returns the underlying error. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to create a custom test context:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom test context bypasses the
contextDeadlineUsed
check in thetransformNetworkError()
with a false value, so it tests the logic inConnectionError.Error()
. Instead, the context returned byWithTimeout()
triggers L344 in "connection.go" which has been tested inTestBackgroundRead
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, good call. Thanks! Can we add a compile-time check to assert that testContext implements context.Context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the assertion is necessary as
testContext
embeds acontext.Context
and is also passed to a context parameter.