@@ -1421,12 +1421,15 @@ def is_retrying():
1421
1421
# be a persistent outage. Attempting to retry in this case will
1422
1422
# most likely be a waste of time.
1423
1423
raise
1424
- except Exception as exc :
1424
+ except PyMongoError as exc :
1425
1425
if not retryable :
1426
1426
raise
1427
- # Add the RetryableWriteError label.
1428
- if (not _retryable_writes_error (exc , max_wire_version )
1429
- or is_retrying ()):
1427
+ # Add the RetryableWriteError label, if applicable.
1428
+ _add_retryable_write_error (exc , max_wire_version )
1429
+ retryable_error = exc .has_error_label ("RetryableWriteError" )
1430
+ if retryable_error :
1431
+ session ._unpin_mongos ()
1432
+ if is_retrying () or not retryable_error :
1430
1433
raise
1431
1434
if bulk :
1432
1435
bulk .retrying = True
@@ -2170,7 +2173,7 @@ def _retryable_error_doc(exc):
2170
2173
return None
2171
2174
2172
2175
2173
- def _retryable_writes_error (exc , max_wire_version ):
2176
+ def _add_retryable_write_error (exc , max_wire_version ):
2174
2177
doc = _retryable_error_doc (exc )
2175
2178
if doc :
2176
2179
code = doc .get ('code' , 0 )
@@ -2183,18 +2186,18 @@ def _retryable_writes_error(exc, max_wire_version):
2183
2186
"to your connection string." )
2184
2187
raise OperationFailure (errmsg , code , exc .details )
2185
2188
if max_wire_version >= 9 :
2186
- # MongoDB 4.4+ utilizes RetryableWriteError.
2187
- return 'RetryableWriteError' in doc .get ('errorLabels' , [])
2189
+ # In MongoDB 4.4+, the server reports the error labels.
2190
+ for label in doc .get ('errorLabels' , []):
2191
+ exc ._add_error_label (label )
2188
2192
else :
2189
2193
if code in helpers ._RETRYABLE_ERROR_CODES :
2190
2194
exc ._add_error_label ("RetryableWriteError" )
2191
- return True
2192
- return False
2193
2195
2194
- if isinstance (exc , ConnectionFailure ):
2196
+ # Connection errors are always retryable except NotMasterError which is
2197
+ # handled above.
2198
+ if (isinstance (exc , ConnectionFailure ) and
2199
+ not isinstance (exc , NotMasterError )):
2195
2200
exc ._add_error_label ("RetryableWriteError" )
2196
- return True
2197
- return False
2198
2201
2199
2202
2200
2203
class _MongoClientErrorHandler (object ):
@@ -2232,7 +2235,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
2232
2235
self .session ._server_session .mark_dirty ()
2233
2236
2234
2237
if issubclass (exc_type , PyMongoError ):
2235
- if exc_val .has_error_label ("TransientTransactionError" ):
2238
+ if (exc_val .has_error_label ("TransientTransactionError" ) or
2239
+ exc_val .has_error_label ("RetryableWriteError" )):
2236
2240
self .session ._unpin_mongos ()
2237
2241
2238
2242
err_ctx = _ErrorContext (
0 commit comments