Skip to content

Commit d3a4958

Browse files
committed
wip update tests
1 parent 58602c7 commit d3a4958

File tree

7 files changed

+278
-47
lines changed

7 files changed

+278
-47
lines changed

pymongo/asynchronous/helpers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,22 @@ async def inner(self: Any, *args: Any, **kwargs: Any) -> Any:
172172
retry_policy = self._retry_policy
173173
attempt = 0
174174
while True:
175+
print("in retry overload", attempt, func, args, kwargs)
175176
try:
176177
res = await func(self, *args, **kwargs)
177178
await retry_policy.record_success(retry=attempt > 0)
179+
print("finished retry overload", attempt, func, args, kwargs)
178180
return res
179181
except PyMongoError as exc:
180182
if not exc.has_error_label("RetryableError"):
183+
print("retry overload no retryable overload", attempt, func, args, kwargs)
181184
raise
182185
attempt += 1
183186
delay = 0
184187
if exc.has_error_label("SystemOverloadedError"):
185188
delay = retry_policy.backoff(attempt)
186189
if not await retry_policy.should_retry(attempt, delay):
190+
print("bailing on the retry", attempt, func, args, kwargs)
187191
raise
188192

189193
# Implement exponential backoff on retry.

pymongo/asynchronous/pool.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,7 @@ def _handle_connection_error(self, error: BaseException, phase: str) -> None:
10411041
# If found, set backoff and add error labels.
10421042
if self.is_sdam or type(error) not in (AutoReconnect, NetworkTimeout):
10431043
return
1044+
print("handling connection error", id(self))
10441045
error._add_error_label("SystemOverloadedError")
10451046
error._add_error_label("RetryableError")
10461047
self.backoff()
@@ -1326,6 +1327,7 @@ async def _get_conn(
13261327
conn = None
13271328
incremented = False
13281329
emitted_event = False
1330+
13291331
try:
13301332
async with self.lock:
13311333
self.active_sockets += 1
@@ -1337,15 +1339,24 @@ async def _get_conn(
13371339
self._raise_if_not_ready(checkout_started_time, emit_event=False)
13381340
while not (self.conns or self._pending < self.max_connecting):
13391341
timeout = deadline - time.monotonic() if deadline else None
1342+
if self._backoff and (self._backoff_connection_time > time.monotonic()):
1343+
timeout = 0.01
13401344
if not await _async_cond_wait(self._max_connecting_cond, timeout):
1345+
# Check whether we should continue to wait for the backoff condition.
1346+
if self._backoff and deadline is None or deadline < time.monotonic():
1347+
print("looping?", id(self))
1348+
if self._backoff_connection_time > time.monotonic():
1349+
print("continue", id(self))
1350+
continue
1351+
print("break", id(self))
1352+
break
13411353
# Timed out, notify the next thread to ensure a
13421354
# timeout doesn't consume the condition.
13431355
if self.conns or self._pending < self.max_connecting:
13441356
self._max_connecting_cond.notify()
13451357
emitted_event = True
13461358
self._raise_wait_queue_timeout(checkout_started_time)
13471359
self._raise_if_not_ready(checkout_started_time, emit_event=False)
1348-
13491360
try:
13501361
conn = self.conns.popleft()
13511362
except IndexError:
@@ -1355,17 +1366,22 @@ async def _get_conn(
13551366
conn = None
13561367
continue
13571368
# See if we need to wait for the backoff period.
1358-
elif self._backoff and (self._backoff_connection_time < time.monotonic()):
1369+
elif self._backoff and (self._backoff_connection_time > time.monotonic()):
1370+
print("wat", id(self))
13591371
continue
13601372
else: # We need to create a new connection
1373+
print("trying a connection", id(self))
13611374
try:
13621375
conn = await self.connect(handler=handler)
13631376
finally:
1377+
print("finished trying a connection", id(self))
13641378
async with self._max_connecting_cond:
13651379
self._pending -= 1
13661380
self._max_connecting_cond.notify()
1381+
13671382
# Catch KeyboardInterrupt, CancelledError, etc. and cleanup.
1368-
except BaseException:
1383+
except BaseException as e:
1384+
print("got an exception", e, id(self))
13691385
if conn:
13701386
# We checked out a socket but authentication failed.
13711387
await conn.close_conn(ConnectionClosedReason.ERROR)
@@ -1393,9 +1409,12 @@ async def _get_conn(
13931409
error=ConnectionCheckOutFailedReason.CONN_ERROR,
13941410
durationMS=duration,
13951411
)
1412+
print("raising the exception", id(self))
13961413
raise
13971414

13981415
conn.active = True
1416+
if self._backoff:
1417+
print("finished get_conn", id(self))
13991418
return conn
14001419

14011420
async def checkin(self, conn: AsyncConnection) -> None:

pymongo/synchronous/helpers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,22 @@ def inner(self: Any, *args: Any, **kwargs: Any) -> Any:
172172
retry_policy = self._retry_policy
173173
attempt = 0
174174
while True:
175+
print("in retry overload", attempt, func, args, kwargs)
175176
try:
176177
res = func(self, *args, **kwargs)
177178
retry_policy.record_success(retry=attempt > 0)
179+
print("finished retry overload", attempt, func, args, kwargs)
178180
return res
179181
except PyMongoError as exc:
180182
if not exc.has_error_label("RetryableError"):
183+
print("retry overload no retryable overload", attempt, func, args, kwargs)
181184
raise
182185
attempt += 1
183186
delay = 0
184187
if exc.has_error_label("SystemOverloadedError"):
185188
delay = retry_policy.backoff(attempt)
186189
if not retry_policy.should_retry(attempt, delay):
190+
print("bailing on the retry", attempt, func, args, kwargs)
187191
raise
188192

189193
# Implement exponential backoff on retry.

pymongo/synchronous/pool.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,7 @@ def _handle_connection_error(self, error: BaseException, phase: str) -> None:
10371037
# If found, set backoff and add error labels.
10381038
if self.is_sdam or type(error) not in (AutoReconnect, NetworkTimeout):
10391039
return
1040+
print("handling connection error", id(self))
10401041
error._add_error_label("SystemOverloadedError")
10411042
error._add_error_label("RetryableError")
10421043
self.backoff()
@@ -1322,6 +1323,7 @@ def _get_conn(
13221323
conn = None
13231324
incremented = False
13241325
emitted_event = False
1326+
13251327
try:
13261328
with self.lock:
13271329
self.active_sockets += 1
@@ -1333,15 +1335,24 @@ def _get_conn(
13331335
self._raise_if_not_ready(checkout_started_time, emit_event=False)
13341336
while not (self.conns or self._pending < self.max_connecting):
13351337
timeout = deadline - time.monotonic() if deadline else None
1338+
if self._backoff and (self._backoff_connection_time > time.monotonic()):
1339+
timeout = 0.01
13361340
if not _cond_wait(self._max_connecting_cond, timeout):
1341+
# Check whether we should continue to wait for the backoff condition.
1342+
if self._backoff and deadline is None or deadline < time.monotonic():
1343+
print("looping?", id(self))
1344+
if self._backoff_connection_time > time.monotonic():
1345+
print("continue", id(self))
1346+
continue
1347+
print("break", id(self))
1348+
break
13371349
# Timed out, notify the next thread to ensure a
13381350
# timeout doesn't consume the condition.
13391351
if self.conns or self._pending < self.max_connecting:
13401352
self._max_connecting_cond.notify()
13411353
emitted_event = True
13421354
self._raise_wait_queue_timeout(checkout_started_time)
13431355
self._raise_if_not_ready(checkout_started_time, emit_event=False)
1344-
13451356
try:
13461357
conn = self.conns.popleft()
13471358
except IndexError:
@@ -1351,17 +1362,22 @@ def _get_conn(
13511362
conn = None
13521363
continue
13531364
# See if we need to wait for the backoff period.
1354-
elif self._backoff and (self._backoff_connection_time < time.monotonic()):
1365+
elif self._backoff and (self._backoff_connection_time > time.monotonic()):
1366+
print("wat", id(self))
13551367
continue
13561368
else: # We need to create a new connection
1369+
print("trying a connection", id(self))
13571370
try:
13581371
conn = self.connect(handler=handler)
13591372
finally:
1373+
print("finished trying a connection", id(self))
13601374
with self._max_connecting_cond:
13611375
self._pending -= 1
13621376
self._max_connecting_cond.notify()
1377+
13631378
# Catch KeyboardInterrupt, CancelledError, etc. and cleanup.
1364-
except BaseException:
1379+
except BaseException as e:
1380+
print("got an exception", e, id(self))
13651381
if conn:
13661382
# We checked out a socket but authentication failed.
13671383
conn.close_conn(ConnectionClosedReason.ERROR)
@@ -1389,9 +1405,12 @@ def _get_conn(
13891405
error=ConnectionCheckOutFailedReason.CONN_ERROR,
13901406
durationMS=duration,
13911407
)
1408+
print("raising the exception", id(self))
13921409
raise
13931410

13941411
conn.active = True
1412+
if self._backoff:
1413+
print("finished get_conn", id(self))
13951414
return conn
13961415

13971416
def checkin(self, conn: Connection) -> None:

requirements/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pytest>=8.2
22
pytest-asyncio>=0.24.0
3+
pytest-timeout
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
{
2+
"description": "auth-network-error-fail",
3+
"schemaVersion": "1.4",
4+
"runOnRequirements": [
5+
{
6+
"minServerVersion": "4.4",
7+
"auth": true,
8+
"serverless": "forbid",
9+
"topologies": [
10+
"single",
11+
"replicaset",
12+
"sharded"
13+
]
14+
}
15+
],
16+
"createEntities": [
17+
{
18+
"client": {
19+
"id": "setupClient",
20+
"useMultipleMongoses": false
21+
}
22+
}
23+
],
24+
"initialData": [
25+
{
26+
"collectionName": "auth-network-error-fail",
27+
"databaseName": "sdam-tests",
28+
"documents": [
29+
{
30+
"_id": 1
31+
},
32+
{
33+
"_id": 2
34+
}
35+
]
36+
}
37+
],
38+
"tests": [
39+
{
40+
"description": "Backoff and fail after network connection error during authentication",
41+
"operations": [
42+
{
43+
"name": "failPoint",
44+
"object": "testRunner",
45+
"arguments": {
46+
"client": "setupClient",
47+
"failPoint": {
48+
"configureFailPoint": "failCommand",
49+
"mode": "alwaysOn",
50+
"data": {
51+
"failCommands": [
52+
"saslContinue"
53+
],
54+
"appName": "authNetworkErrorFailTest",
55+
"closeConnection": true
56+
}
57+
}
58+
}
59+
},
60+
{
61+
"name": "createEntities",
62+
"object": "testRunner",
63+
"arguments": {
64+
"entities": [
65+
{
66+
"client": {
67+
"id": "client",
68+
"useMultipleMongoses": false,
69+
"observeEvents": [
70+
"commandStartedEvent",
71+
"poolBackoffEvent",
72+
"poolReadyEvent",
73+
"poolClearEvent"
74+
],
75+
"uriOptions": {
76+
"retryWrites": false,
77+
"appname": "authNetworkErrorFailTest"
78+
}
79+
}
80+
},
81+
{
82+
"database": {
83+
"id": "database",
84+
"client": "client",
85+
"databaseName": "sdam-tests"
86+
}
87+
},
88+
{
89+
"collection": {
90+
"id": "collection",
91+
"database": "database",
92+
"collectionName": "auth-network-error-fail"
93+
}
94+
}
95+
]
96+
}
97+
},
98+
{
99+
"name": "insertMany",
100+
"object": "collection",
101+
"arguments": {
102+
"documents": [
103+
{
104+
"_id": 3
105+
},
106+
{
107+
"_id": 4
108+
}
109+
]
110+
},
111+
"expectError": {
112+
"isError": true
113+
}
114+
}
115+
],
116+
"expectEvents": [
117+
{
118+
"client": "client",
119+
"eventType": "command",
120+
"events": []
121+
},
122+
{
123+
"client": "client",
124+
"eventType": "cmap",
125+
"events": [
126+
{
127+
"poolReadyEvent": {}
128+
},
129+
{
130+
"poolBackoffEvent": {
131+
"attempt": 1
132+
}
133+
},
134+
{
135+
"poolBackoffEvent": {
136+
"attempt": 2
137+
}
138+
},
139+
{
140+
"poolBackoffEvent": {
141+
"attempt": 3
142+
}
143+
},
144+
{
145+
"poolBackoffEvent": {
146+
"attempt": 4
147+
}
148+
}
149+
]
150+
}
151+
]
152+
}
153+
]
154+
}

0 commit comments

Comments
 (0)