0
0
mirror of https://github.com/python/cpython.git synced 2024-11-21 21:09:37 +01:00

gh-124858: fix happy eyeballs refcyles (#124859)

This commit is contained in:
Thomas Grainger 2024-10-03 00:32:31 +01:00 committed by GitHub
parent 6810928927
commit c066bf5535
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 32 additions and 6 deletions

View File

@ -17,7 +17,6 @@ import collections
import collections.abc
import concurrent.futures
import errno
import functools
import heapq
import itertools
import os
@ -1140,11 +1139,18 @@ class BaseEventLoop(events.AbstractEventLoop):
except OSError:
continue
else: # using happy eyeballs
sock, _, _ = await staggered.staggered_race(
(functools.partial(self._connect_sock,
exceptions, addrinfo, laddr_infos)
for addrinfo in infos),
happy_eyeballs_delay, loop=self)
sock = (await staggered.staggered_race(
(
# can't use functools.partial as it keeps a reference
# to exceptions
lambda addrinfo=addrinfo: self._connect_sock(
exceptions, addrinfo, laddr_infos
)
for addrinfo in infos
),
happy_eyeballs_delay,
loop=self,
))[0] # can't use sock, _, _ as it keeks a reference to exceptions
if sock is None:
exceptions = [exc for sub in exceptions for exc in sub]

View File

@ -133,6 +133,7 @@ async def staggered_race(coro_fns, delay, *, loop=None):
raise d.exception()
return winner_result, winner_index, exceptions
finally:
del exceptions
# Make sure no tasks are left running if we leave this function
for t in running_tasks:
t.cancel()

View File

@ -1200,6 +1200,24 @@ class StreamTests(test_utils.TestCase):
messages = self._basetest_unhandled_exceptions(handle_echo)
self.assertEqual(messages, [])
def test_open_connection_happy_eyeball_refcycles(self):
port = socket_helper.find_unused_port()
async def main():
exc = None
try:
await asyncio.open_connection(
host="localhost",
port=port,
happy_eyeballs_delay=0.25,
)
except* OSError as excs:
# can't use assertRaises because that clears frames
exc = excs.exceptions[0]
self.assertIsNotNone(exc)
self.assertListEqual(gc.get_referrers(exc), [])
asyncio.run(main())
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1 @@
Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay``