mirror of https://github.com/python/cpython
gh-124858: fix happy eyeballs refcyles (#124859)
This commit is contained in:
parent
6810928927
commit
c066bf5535
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay``
|
Loading…
Reference in New Issue