|
Investigating this further, the change is possible by only modifying Server#ProcessHandshakeError, although the logic is somewhat convoluted:
func (s *Server) ProcessHandshakeError(...) {
|
// ...
|
isTimeout := func(err error) bool {
|
// Handle any self-reporting timeout.
|
if os.IsTimeout(err) {
|
return true
|
}
|
// Extract any wrapped errors from a *net.OpError.
|
if opErr, ok := err.(*net.OpError); ok {
|
err = opErr.Err
|
}
|
|
// Extract any wrapped errors that implement Unwrap()
|
for {
|
wrapper, ok := err.(interface{ Unwrap() error })
|
if !ok {
|
break
|
}
|
err = wrapper.Unwrap()
|
}
|
|
return err == context.Canceled ||
|
err == context.DeadlineExceeded ||
|
// Handle the case where the error has been replaced by net.errCanceled, which isn't exported
|
// and can't be compared directly.
|
err.Error() == "operation was canceled"
|
}
|
|
if isTimeout(wrappedConnErr) {
|
return
|
}
|
// ...
|
}
|
It's unclear how many cases the Unwrap loop handles, but could be important for completeness. I tested the code using an explicitly cancelled or timed-out Context when calling DialContext in topology.connection#connect and only two conditions were hit:
- os.IsTimeout caught Context deadline exceeded conditions
- err.Error() == "operation was canceled" caught Context canceled conditions
We could probably clean that logic up by handling the most common conditions (i.e. *net.OpError with net-specific error messages), but it basically works.
|