@@ -273,7 +273,7 @@ func (s *Server) Connection(ctx context.Context) (driver.Connection, error) {
273
273
}
274
274
275
275
// ProcessHandshakeError implements SDAM error handling for errors that occur before a connection finishes handshaking.
276
- // ctxErr is any error caused by the context passed to Server# Connection() and is used to determine whether or not an
276
+ // ctxErr is any error caused by the context passed to Server. Connection() and is used to determine whether or not an
277
277
// operation-scoped context deadline or cancellation was the cause of the handshake error.
278
278
func (s * Server ) ProcessHandshakeError (err , ctxErr error , startingGenerationNumber uint64 , serviceID * primitive.ObjectID ) {
279
279
// Ignore the error if the server is behind a load balancer but the service ID is unknown. This indicates that the
@@ -292,29 +292,37 @@ func (s *Server) ProcessHandshakeError(err, ctxErr error, startingGenerationNumb
292
292
return
293
293
}
294
294
295
- isTimeout := func (err error ) bool {
295
+ isTimeoutOrCanceled := func (err error ) bool {
296
296
for err != nil {
297
+ // Check for errors that implement the "net.Error" interface and self-report as timeout
298
+ // errors. Includes some "*net.OpError" errors and "context.DeadlineExceeded".
297
299
if netErr , ok := err .(net.Error ); ok && netErr .Timeout () {
298
300
return true
299
301
}
300
- // Handle the case where an error has been replaced by "net.errCanceled", which isn't
301
- // exported and can't be compared directly. In this case, just compare the error message.
302
- if err .Error () == "operation was canceled" {
302
+ // Check for context cancellation. Also handle the case where the cancellation error has
303
+ // been replaced by "net.errCanceled" (which isn't exported and can't be compared
304
+ // directly) by checking the error message.
305
+ if err == context .Canceled || err .Error () == "operation was canceled" {
303
306
return true
304
307
}
305
- if wrapper , ok := err .( interface { Unwrap () error }); ok {
306
- err = wrapper . Unwrap ()
307
- } else {
308
+
309
+ wrapper , ok := err .( interface { Unwrap () error } )
310
+ if ! ok {
308
311
break
309
312
}
313
+ err = wrapper .Unwrap ()
310
314
}
311
315
312
316
return false
313
317
}
314
318
315
- // Ignore errors that indicate a client-side timeout occurred when using an operation-scoped
316
- // deadline (i.e. not using connectTimeoutMS as the connection timeout).
317
- if (ctxErr == context .DeadlineExceeded || ctxErr == context .Canceled ) && isTimeout (wrappedConnErr ) {
319
+ // Ignore errors that indicate a client-side timeout occurred when the context passed into an
320
+ // operation timed out or was canceled (i.e. errors caused by an operation-scoped timeout).
321
+ // Timeouts caused by reaching connectTimeoutMS or other non-operation-scoped timeouts should
322
+ // still clear the pool.
323
+ // TODO(GODRIVER-2038): Remove this condition when connections are no longer created with an
324
+ // operation-scoped timeout.
325
+ if ctxErr != nil && isTimeoutOrCanceled (wrappedConnErr ) {
318
326
return
319
327
}
320
328
0 commit comments