Skip to content

Commit 4457714

Browse files
authored
PYTHON-2082 Unpin session after RetryableWriteErrors from commitTransaction (#451)
PYTHON-2154 PYTHON-2189 Remove 4.5 transaction test workarounds
1 parent 26913ea commit 4457714

File tree

3 files changed

+18
-21
lines changed

3 files changed

+18
-21
lines changed

pymongo/mongo_client.py

+17-13
Original file line numberDiff line numberDiff line change
@@ -1421,12 +1421,15 @@ def is_retrying():
14211421
# be a persistent outage. Attempting to retry in this case will
14221422
# most likely be a waste of time.
14231423
raise
1424-
except Exception as exc:
1424+
except PyMongoError as exc:
14251425
if not retryable:
14261426
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:
14301433
raise
14311434
if bulk:
14321435
bulk.retrying = True
@@ -2170,7 +2173,7 @@ def _retryable_error_doc(exc):
21702173
return None
21712174

21722175

2173-
def _retryable_writes_error(exc, max_wire_version):
2176+
def _add_retryable_write_error(exc, max_wire_version):
21742177
doc = _retryable_error_doc(exc)
21752178
if doc:
21762179
code = doc.get('code', 0)
@@ -2183,18 +2186,18 @@ def _retryable_writes_error(exc, max_wire_version):
21832186
"to your connection string.")
21842187
raise OperationFailure(errmsg, code, exc.details)
21852188
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)
21882192
else:
21892193
if code in helpers._RETRYABLE_ERROR_CODES:
21902194
exc._add_error_label("RetryableWriteError")
2191-
return True
2192-
return False
21932195

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)):
21952200
exc._add_error_label("RetryableWriteError")
2196-
return True
2197-
return False
21982201

21992202

22002203
class _MongoClientErrorHandler(object):
@@ -2232,7 +2235,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
22322235
self.session._server_session.mark_dirty()
22332236

22342237
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")):
22362240
self.session._unpin_mongos()
22372241

22382242
err_ctx = _ErrorContext(

test/test_examples.py

-1
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,6 @@ def test_misc(self):
842842

843843

844844
class TestTransactionExamples(IntegrationTest):
845-
@client_context.require_version_max(4, 4, 99) # PYTHON-2154 skip on 4.5+
846845
@client_context.require_transactions
847846
def test_transactions(self):
848847
# Transaction examples

test/test_transactions.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,7 @@ def create_test(scenario_def, test, name):
415415
@client_context.require_test_commands
416416
@client_context.require_transactions
417417
def run_scenario(self):
418-
try:
419-
self.run_scenario(scenario_def, test)
420-
except OperationFailure as exc:
421-
if (client_context.version.at_least(4, 5) and
422-
client_context.is_mongos and exc.code == 13388):
423-
self.skipTest('PYTHON-2189 Ignoring StaleConfig error: %r' % (
424-
exc.details))
418+
self.run_scenario(scenario_def, test)
425419

426420
return run_scenario
427421

0 commit comments

Comments
 (0)