Skip to content

Commit 0948cdf

Browse files
committed
CP review
1 parent 863704e commit 0948cdf

6 files changed

Lines changed: 106 additions & 118 deletions

File tree

pymongo/asynchronous/client_session.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ async def reset(self) -> None:
467467
self.sharded = False
468468
self.recovery_token = None
469469
self.attempt = 0
470+
self.has_completed_command = False
470471

471472
def __del__(self) -> None:
472473
if self.conn_mgr:

pymongo/synchronous/client_session.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ def reset(self) -> None:
465465
self.sharded = False
466466
self.recovery_token = None
467467
self.attempt = 0
468+
self.has_completed_command = False
468469

469470
def __del__(self) -> None:
470471
if self.conn_mgr:

test/asynchronous/test_retryable_writes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,6 @@ def failed(event: CommandFailedEvent) -> None:
732732
async def test_03_drivers_return_the_correct_error_when_receiving_some_errors_with_NoWritesPerformed_and_some_without_NoWritesPerformed(
733733
self
734734
) -> None:
735-
# TODO: read the expected behavior and add breakpoint() to the retry loop
736735
# Create a client with retryWrites=true.
737736
listener = OvertCommandListener()
738737

@@ -761,7 +760,7 @@ async def test_03_drivers_return_the_correct_error_when_receiving_some_errors_wi
761760
}
762761

763762
def failed(event: CommandFailedEvent) -> None:
764-
# Configure the fail point command only if the the failed event is for the 91 error configured in step 2.
763+
# Configure the fail point command only if the failed event is for the 91 error configured in step 2.
765764
if listener.failed_events:
766765
return
767766
assert event.failure["code"] == 91

test/asynchronous/test_transactions.py

Lines changed: 51 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import sys
2121
import time
2222
from io import BytesIO
23+
from unittest.mock import patch
2324

2425
import pymongo
2526
from gridfs.asynchronous.grid_file import AsyncGridFS, AsyncGridFSBucket
@@ -654,66 +655,57 @@ async def callback(session):
654655
async def test_4_retry_backoff_is_enforced(self):
655656
client = async_client_context.client
656657
coll = client[self.db.name].test
657-
# patch random to make it deterministic -- once to effectively have
658-
# no backoff and the second time with "max" backoff (always waiting the longest
659-
# possible time)
660-
_original_random_random = random.random
661-
662-
def always_one():
663-
return 1
664-
665-
def always_zero():
666-
return 0
667-
668-
random.random = always_zero
669-
# set fail point to trigger transaction failure and trigger backoff
670-
await self.set_fail_point(
671-
{
672-
"configureFailPoint": "failCommand",
673-
"mode": {"times": 13},
674-
"data": {
675-
"failCommands": ["commitTransaction"],
676-
"errorCode": 251,
677-
},
678-
}
679-
)
680-
self.addAsyncCleanup(
681-
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
682-
)
683-
684-
async def callback(session):
685-
await coll.insert_one({}, session=session)
686-
687-
start = time.monotonic()
688-
async with self.client.start_session() as s:
689-
await s.with_transaction(callback)
690-
end = time.monotonic()
691-
no_backoff_time = end - start
692-
693-
random.random = always_one
694-
# set fail point to trigger transaction failure and trigger backoff
695-
await self.set_fail_point(
696-
{
697-
"configureFailPoint": "failCommand",
698-
"mode": {
699-
"times": 13
700-
}, # sufficiently high enough such that the time effect of backoff is noticeable
701-
"data": {
702-
"failCommands": ["commitTransaction"],
703-
"errorCode": 251,
704-
},
705-
}
706-
)
707-
self.addAsyncCleanup(
708-
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
709-
)
710-
start = time.monotonic()
711-
async with self.client.start_session() as s:
712-
await s.with_transaction(callback)
713-
end = time.monotonic()
714-
self.assertLess(abs(end - start - (no_backoff_time + 2.2)), 1) # sum of 13 backoffs is 2.2
658+
end = start = no_backoff_time = 0
659+
660+
# Make random.random always return 0 (no backoff)
661+
with patch.object(random, "random", return_value=0):
662+
# set fail point to trigger transaction failure and trigger backoff
663+
await self.set_fail_point(
664+
{
665+
"configureFailPoint": "failCommand",
666+
"mode": {"times": 13},
667+
"data": {
668+
"failCommands": ["commitTransaction"],
669+
"errorCode": 251,
670+
},
671+
}
672+
)
673+
self.addAsyncCleanup(
674+
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
675+
)
715676

716-
random.random = _original_random_random
677+
async def callback(session):
678+
await coll.insert_one({}, session=session)
679+
680+
start = time.monotonic()
681+
async with self.client.start_session() as s:
682+
await s.with_transaction(callback)
683+
end = time.monotonic()
684+
no_backoff_time = end - start
685+
686+
# Make random.random always return 1 (max backoff)
687+
with patch.object(random, "random", return_value=1):
688+
# set fail point to trigger transaction failure and trigger backoff
689+
await self.set_fail_point(
690+
{
691+
"configureFailPoint": "failCommand",
692+
"mode": {
693+
"times": 13
694+
}, # sufficiently high enough such that the time effect of backoff is noticeable
695+
"data": {
696+
"failCommands": ["commitTransaction"],
697+
"errorCode": 251,
698+
},
699+
}
700+
)
701+
self.addAsyncCleanup(
702+
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
703+
)
704+
start = time.monotonic()
705+
async with self.client.start_session() as s:
706+
await s.with_transaction(callback)
707+
end = time.monotonic()
708+
self.assertLess(abs(end - start - (no_backoff_time + 2.2)), 1) # sum of 5 backoffs is 2.2
717709

718710

719711
class TestOptionsInsideTransactionProse(AsyncTransactionsBase):

test/test_retryable_writes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,6 @@ def failed(event: CommandFailedEvent) -> None:
728728
def test_03_drivers_return_the_correct_error_when_receiving_some_errors_with_NoWritesPerformed_and_some_without_NoWritesPerformed(
729729
self
730730
) -> None:
731-
# TODO: read the expected behavior and add breakpoint() to the retry loop
732731
# Create a client with retryWrites=true.
733732
listener = OvertCommandListener()
734733

@@ -757,7 +756,7 @@ def test_03_drivers_return_the_correct_error_when_receiving_some_errors_with_NoW
757756
}
758757

759758
def failed(event: CommandFailedEvent) -> None:
760-
# Configure the fail point command only if the the failed event is for the 91 error configured in step 2.
759+
# Configure the fail point command only if the failed event is for the 91 error configured in step 2.
761760
if listener.failed_events:
762761
return
763762
assert event.failure["code"] == 91

test/test_transactions.py

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import sys
2121
import time
2222
from io import BytesIO
23+
from unittest.mock import patch
2324

2425
import pymongo
2526
from gridfs.synchronous.grid_file import GridFS, GridFSBucket
@@ -642,62 +643,57 @@ def callback(session):
642643
def test_4_retry_backoff_is_enforced(self):
643644
client = client_context.client
644645
coll = client[self.db.name].test
645-
# patch random to make it deterministic -- once to effectively have
646-
# no backoff and the second time with "max" backoff (always waiting the longest
647-
# possible time)
648-
_original_random_random = random.random
649-
650-
def always_one():
651-
return 1
652-
653-
def always_zero():
654-
return 0
655-
656-
random.random = always_zero
657-
# set fail point to trigger transaction failure and trigger backoff
658-
self.set_fail_point(
659-
{
660-
"configureFailPoint": "failCommand",
661-
"mode": {"times": 13},
662-
"data": {
663-
"failCommands": ["commitTransaction"],
664-
"errorCode": 251,
665-
},
666-
}
667-
)
668-
self.addCleanup(self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"})
669-
670-
def callback(session):
671-
coll.insert_one({}, session=session)
672-
673-
start = time.monotonic()
674-
with self.client.start_session() as s:
675-
s.with_transaction(callback)
676-
end = time.monotonic()
677-
no_backoff_time = end - start
678-
679-
random.random = always_one
680-
# set fail point to trigger transaction failure and trigger backoff
681-
self.set_fail_point(
682-
{
683-
"configureFailPoint": "failCommand",
684-
"mode": {
685-
"times": 13
686-
}, # sufficiently high enough such that the time effect of backoff is noticeable
687-
"data": {
688-
"failCommands": ["commitTransaction"],
689-
"errorCode": 251,
690-
},
691-
}
692-
)
693-
self.addCleanup(self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"})
694-
start = time.monotonic()
695-
with self.client.start_session() as s:
696-
s.with_transaction(callback)
697-
end = time.monotonic()
698-
self.assertLess(abs(end - start - (no_backoff_time + 2.2)), 1) # sum of 13 backoffs is 2.2
646+
end = start = no_backoff_time = 0
647+
648+
# Make random.random always return 0 (no backoff)
649+
with patch.object(random, "random", return_value=0):
650+
# set fail point to trigger transaction failure and trigger backoff
651+
self.set_fail_point(
652+
{
653+
"configureFailPoint": "failCommand",
654+
"mode": {"times": 13},
655+
"data": {
656+
"failCommands": ["commitTransaction"],
657+
"errorCode": 251,
658+
},
659+
}
660+
)
661+
self.addCleanup(
662+
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
663+
)
699664

700-
random.random = _original_random_random
665+
def callback(session):
666+
coll.insert_one({}, session=session)
667+
668+
start = time.monotonic()
669+
with self.client.start_session() as s:
670+
s.with_transaction(callback)
671+
end = time.monotonic()
672+
no_backoff_time = end - start
673+
674+
# Make random.random always return 1 (max backoff)
675+
with patch.object(random, "random", return_value=1):
676+
# set fail point to trigger transaction failure and trigger backoff
677+
self.set_fail_point(
678+
{
679+
"configureFailPoint": "failCommand",
680+
"mode": {
681+
"times": 13
682+
}, # sufficiently high enough such that the time effect of backoff is noticeable
683+
"data": {
684+
"failCommands": ["commitTransaction"],
685+
"errorCode": 251,
686+
},
687+
}
688+
)
689+
self.addCleanup(
690+
self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"}
691+
)
692+
start = time.monotonic()
693+
with self.client.start_session() as s:
694+
s.with_transaction(callback)
695+
end = time.monotonic()
696+
self.assertLess(abs(end - start - (no_backoff_time + 2.2)), 1) # sum of 5 backoffs is 2.2
701697

702698

703699
class TestOptionsInsideTransactionProse(TransactionsBase):

0 commit comments

Comments
 (0)