8000 [3.13] gh-124858: fix happy eyeballs refcyles (GH-124859) (#124912) · python/cpython@e596740 · GitHub
[go: up one dir, main page]

10000
Skip to content

Commit e596740

Browse files
[3.13] gh-124858: fix happy eyeballs refcyles (GH-124859) (#124912)
gh-124858: fix happy eyeballs refcyles (GH-124859) (cherry picked from commit c066bf5) Co-authored-by: Thomas Grainger <tagrain@gmail.com>
1 parent 77d7998 commit e596740

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

Lib/asyncio/base_events.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import collections.abc
1818
import concurrent.futures
1919
import errno
20-
import functools
2120
import heapq
2221
import itertools
2322
import os
@@ -1140,11 +1139,18 @@ async def create_connection(
11401139
except OSError:
11411140
continue
11421141
else: # using happy eyeballs
1143-
sock, _, _ = await staggered.staggered_race(
1144-
(functools.partial(self._connect_sock,
1145-
exceptions, addrinfo, laddr_infos)
1146-
for addrinfo in infos),
1147-
happy_eyeballs_delay, loop=self)
1142+
sock = (await staggered.staggered_race(
1143+
(
1144+
# can't use functools.partial as it keeps a reference
1145+
# to exceptions
1146+
lambda addrinfo=addrinfo: self._connect_sock(
1147+
exceptions, addrinfo, laddr_infos
1148+
)
1149+
for addrinfo in infos
1150+
),
1151+
happy_eyeballs_delay,
1152+
loop=self,
1153+
))[0] # can't use sock, _, _ as it keeks a reference to exceptions
11481154

11491155
if sock is None:
11501156
exceptions = [exc for sub in exceptions for exc in sub]

Lib/asyncio/staggered.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ async def run_one_coro(ok_to_start, previous_failed) -> None:
144144
raise d.exception()
145145
return winner_result, winner_index, exceptions
146146
finally:
147+
del exceptions
147148
# Make sure no tasks are left running if we leave this function
148149
for t in running_tasks:
149150
t.cancel()

Lib/test/test_asyncio/test_streams.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,24 @@ async def handle_echo(reader, writer):
12461246
messages = self._basetest_unhandled_exceptions(handle_echo)
12471247
self.assertEqual(messages, [])
12481248

1249+
def test_open_connection_happy_eyeball_refcycles(self):
1250+
port = socket_helper.find_unused_port()
1251+
async def main():
1252+
exc = None
1253+
try:
1254+
await asyncio.open_connection(
1255+
host="localhost",
1256+
port=port,
1257+
happy_eyeballs_delay=0.25,
1258+
)
1259+
except* OSError as excs:
1260+
# can't use assertRaises because that clears frames
1261+
exc = excs.exceptions[0]
1262+
self.assertIsNotNone(exc)
1263+
self.assertListEqual(gc.get_referrers(exc), [])
1264+
1265+
asyncio.run(main())
1266+
12491267

12501268
if __name__ == '__main__':
12511269
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay``

0 commit comments

Comments
 (0)
0