Skip to content

Commit af54ac3

Browse files
committed
Add more tests
1 parent 4926c3a commit af54ac3

7 files changed

Lines changed: 3015 additions & 1037 deletions

File tree

pymongo/asynchronous/collection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2946,6 +2946,7 @@ async def _aggregate(
29462946
session,
29472947
retryable=not cmd._performs_write,
29482948
operation=_Op.AGGREGATE,
2949+
is_aggregate_write=cmd._performs_write,
29492950
)
29502951

29512952
async def aggregate(

pymongo/asynchronous/mongo_client.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,7 @@ async def _retry_internal(
20102010
retryable: bool = False,
20112011
operation_id: Optional[int] = None,
20122012
is_run_command: bool = False,
2013+
is_aggregate_write: bool = False,
20132014
) -> T:
20142015
"""Internal retryable helper for all client transactions.
20152016
@@ -2022,6 +2023,7 @@ async def _retry_internal(
20222023
:param read_pref: Topology of read operation, defaults to None
20232024
:param retryable: If the operation should be retried once, defaults to None
20242025
:param is_run_command: If this is a runCommand operation, defaults to False
2026+
:param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
20252027
20262028
:return: Output of the calling func()
20272029
"""
@@ -2037,6 +2039,7 @@ async def _retry_internal(
20372039
retryable=retryable,
20382040
operation_id=operation_id,
20392041
is_run_command=is_run_command,
2042+
is_aggregate_write=is_aggregate_write,
20402043
).run()
20412044

20422045
async def _retryable_read(
@@ -2049,6 +2052,7 @@ async def _retryable_read(
20492052
retryable: bool = True,
20502053
operation_id: Optional[int] = None,
20512054
is_run_command: bool = False,
2055+
is_aggregate_write: bool = False,
20522056
) -> T:
20532057
"""Execute an operation with consecutive retries if possible
20542058
@@ -2065,6 +2069,7 @@ async def _retryable_read(
20652069
:param retryable: if we should attempt retries
20662070
(may not always be supported even if supplied), defaults to False
20672071
:param is_run_command: If this is a runCommand operation, defaults to False.
2072+
:param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
20682073
"""
20692074

20702075
# Ensure that the client supports retrying on reads and there is no session in
@@ -2084,6 +2089,7 @@ async def _retryable_read(
20842089
retryable=retryable,
20852090
operation_id=operation_id,
20862091
is_run_command=is_run_command,
2092+
is_aggregate_write=is_aggregate_write,
20872093
)
20882094

20892095
async def _retryable_write(
@@ -2754,6 +2760,7 @@ def __init__(
27542760
retryable: bool = False,
27552761
operation_id: Optional[int] = None,
27562762
is_run_command: bool = False,
2763+
is_aggregate_write: bool = False,
27572764
):
27582765
self._last_error: Optional[Exception] = None
27592766
self._retrying = False
@@ -2777,6 +2784,7 @@ def __init__(
27772784
self._operation_id = operation_id
27782785
self._attempt_number = 0
27792786
self._is_run_command = is_run_command
2787+
self._is_aggregate_write = is_aggregate_write
27802788

27812789
async def run(self) -> T:
27822790
"""Runs the supplied func() and attempts a retry
@@ -2822,6 +2830,9 @@ async def run(self) -> T:
28222830
self._client.options.retry_reads and self._client.options.retry_writes
28232831
):
28242832
raise
2833+
if self._is_aggregate_write and not self._client.options.retry_writes:
2834+
raise
2835+
28252836
# Execute specialized catch on read
28262837
if self._is_read:
28272838
if isinstance(exc, (ConnectionFailure, OperationFailure)):
@@ -2870,9 +2881,9 @@ async def run(self) -> T:
28702881
always_retryable = exc_to_check.has_error_label("RetryableError") and overloaded
28712882

28722883
# Always retry abortTransaction and commitTransaction up to once
2873-
if not (self._client.options.retry_writes and self._retryable) and (
2874-
not always_retryable
2875-
and self._operation not in ["abortTransaction", "commitTransaction"]
2884+
if self._operation not in ["abortTransaction", "commitTransaction"] and (
2885+
not self._client.options.retry_writes
2886+
or not (self._retryable or always_retryable)
28762887
):
28772888
raise
28782889
if retryable_write_label or always_retryable:

pymongo/synchronous/collection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,6 +2939,7 @@ def _aggregate(
29392939
session,
29402940
retryable=not cmd._performs_write,
29412941
operation=_Op.AGGREGATE,
2942+
is_aggregate_write=cmd._performs_write,
29422943
)
29432944

29442945
def aggregate(

pymongo/synchronous/mongo_client.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,7 @@ def _retry_internal(
20062006
retryable: bool = False,
20072007
operation_id: Optional[int] = None,
20082008
is_run_command: bool = False,
2009+
is_aggregate_write: bool = False,
20092010
) -> T:
20102011
"""Internal retryable helper for all client transactions.
20112012
@@ -2018,6 +2019,7 @@ def _retry_internal(
20182019
:param read_pref: Topology of read operation, defaults to None
20192020
:param retryable: If the operation should be retried once, defaults to None
20202021
:param is_run_command: If this is a runCommand operation, defaults to False
2022+
:param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
20212023
20222024
:return: Output of the calling func()
20232025
"""
@@ -2033,6 +2035,7 @@ def _retry_internal(
20332035
retryable=retryable,
20342036
operation_id=operation_id,
20352037
is_run_command=is_run_command,
2038+
is_aggregate_write=is_aggregate_write,
20362039
).run()
20372040

20382041
def _retryable_read(
@@ -2045,6 +2048,7 @@ def _retryable_read(
20452048
retryable: bool = True,
20462049
operation_id: Optional[int] = None,
20472050
is_run_command: bool = False,
2051+
is_aggregate_write: bool = False,
20482052
) -> T:
20492053
"""Execute an operation with consecutive retries if possible
20502054
@@ -2061,6 +2065,7 @@ def _retryable_read(
20612065
:param retryable: if we should attempt retries
20622066
(may not always be supported even if supplied), defaults to False
20632067
:param is_run_command: If this is a runCommand operation, defaults to False.
2068+
:param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
20642069
"""
20652070

20662071
# Ensure that the client supports retrying on reads and there is no session in
@@ -2080,6 +2085,7 @@ def _retryable_read(
20802085
retryable=retryable,
20812086
operation_id=operation_id,
20822087
is_run_command=is_run_command,
2088+
is_aggregate_write=is_aggregate_write,
20832089
)
20842090

20852091
def _retryable_write(
@@ -2744,6 +2750,7 @@ def __init__(
27442750
retryable: bool = False,
27452751
operation_id: Optional[int] = None,
27462752
is_run_command: bool = False,
2753+
is_aggregate_write: bool = False,
27472754
):
27482755
self._last_error: Optional[Exception] = None
27492756
self._retrying = False
@@ -2767,6 +2774,7 @@ def __init__(
27672774
self._operation_id = operation_id
27682775
self._attempt_number = 0
27692776
self._is_run_command = is_run_command
2777+
self._is_aggregate_write = is_aggregate_write
27702778

27712779
def run(self) -> T:
27722780
"""Runs the supplied func() and attempts a retry
@@ -2812,6 +2820,9 @@ def run(self) -> T:
28122820
self._client.options.retry_reads and self._client.options.retry_writes
28132821
):
28142822
raise
2823+
if self._is_aggregate_write and not self._client.options.retry_writes:
2824+
raise
2825+
28152826
# Execute specialized catch on read
28162827
if self._is_read:
28172828
if isinstance(exc, (ConnectionFailure, OperationFailure)):
@@ -2860,9 +2871,9 @@ def run(self) -> T:
28602871
always_retryable = exc_to_check.has_error_label("RetryableError") and overloaded
28612872

28622873
# Always retry abortTransaction and commitTransaction up to once
2863-
if not (self._client.options.retry_writes and self._retryable) and (
2864-
not always_retryable
2865-
and self._operation not in ["abortTransaction", "commitTransaction"]
2874+
if self._operation not in ["abortTransaction", "commitTransaction"] and (
2875+
not self._client.options.retry_writes
2876+
or not (self._retryable or always_retryable)
28662877
):
28672878
raise
28682879
if retryable_write_label or always_retryable:

0 commit comments

Comments
 (0)