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 collections.abc
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import errno
|
import errno
|
||||||
import functools
|
|
||||||
import heapq
|
import heapq
|
||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
|
@ -1140,11 +1139,18 @@ class BaseEventLoop(events.AbstractEventLoop):
|
||||||
except OSError:
|
except OSError:
|
||||||
continue
|
continue
|
||||||
else: # using happy eyeballs
|
else: # using happy eyeballs
|
||||||
sock, _, _ = await staggered.staggered_race(
|
sock = (await staggered.staggered_race(
|
||||||
(functools.partial(self._connect_sock,
|
(
|
||||||
exceptions, addrinfo, laddr_infos)
|
# can't use functools.partial as it keeps a reference
|
||||||
for addrinfo in infos),
|
# to exceptions
|
||||||
happy_eyeballs_delay, loop=self)
|
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:
|
if sock is None:
|
||||||
exceptions = [exc for sub in exceptions for exc in sub]
|
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()
|
raise d.exception()
|
||||||
return winner_result, winner_index, exceptions
|
return winner_result, winner_index, exceptions
|
||||||
finally:
|
finally:
|
||||||
|
del exceptions
|
||||||
# Make sure no tasks are left running if we leave this function
|
# Make sure no tasks are left running if we leave this function
|
||||||
for t in running_tasks:
|
for t in running_tasks:
|
||||||
t.cancel()
|
t.cancel()
|
||||||
|
|
|
@ -1200,6 +1200,24 @@ class StreamTests(test_utils.TestCase):
|
||||||
messages = self._basetest_unhandled_exceptions(handle_echo)
|
messages = self._basetest_unhandled_exceptions(handle_echo)
|
||||||
self.assertEqual(messages, [])
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.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