mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-127529: Correct asyncio's accept_connection
behaviour for handling ConnectionAbortedError
(#127532)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
parent
bb2dfadb92
commit
830e10651b
3 changed files with 36 additions and 3 deletions
|
@ -180,9 +180,13 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
|
|||
logger.debug("%r got a new connection from %r: %r",
|
||||
server, addr, conn)
|
||||
conn.setblocking(False)
|
||||
except (BlockingIOError, InterruptedError, ConnectionAbortedError):
|
||||
# Early exit because the socket accept buffer is empty.
|
||||
return None
|
||||
except ConnectionAbortedError:
|
||||
# Discard connections that were aborted before accept().
|
||||
continue
|
||||
except (BlockingIOError, InterruptedError):
|
||||
# Early exit because of a signal or
|
||||
# the socket accept buffer is empty.
|
||||
return
|
||||
except OSError as exc:
|
||||
# There's nowhere to send the error, so just log it.
|
||||
if exc.errno in (errno.EMFILE, errno.ENFILE,
|
||||
|
|
|
@ -364,6 +364,31 @@ class BaseSelectorEventLoopTests(test_utils.TestCase):
|
|||
self.loop.run_until_complete(asyncio.sleep(0))
|
||||
self.assertEqual(sock.accept.call_count, backlog)
|
||||
|
||||
def test_accept_connection_skip_connectionabortederror(self):
|
||||
sock = mock.Mock()
|
||||
|
||||
def mock_sock_accept():
|
||||
# mock accept(2) returning -ECONNABORTED every-other
|
||||
# time that it's called. This applies most to OpenBSD
|
||||
# whose sockets generate this errno more reproducibly than
|
||||
# Linux and other OS.
|
||||
if sock.accept.call_count % 2 == 0:
|
||||
raise ConnectionAbortedError
|
||||
return (mock.Mock(), mock.Mock())
|
||||
|
||||
sock.accept.side_effect = mock_sock_accept
|
||||
backlog = 100
|
||||
# test that _accept_connection's loop calls sock.accept
|
||||
# all 100 times, continuing past ConnectionAbortedError
|
||||
# instead of unnecessarily returning early
|
||||
mock_obj = mock.patch.object
|
||||
with mock_obj(self.loop, '_accept_connection2') as accept2_mock:
|
||||
self.loop._accept_connection(
|
||||
mock.Mock(), sock, backlog=backlog)
|
||||
# as in test_accept_connection_multiple avoid task pending
|
||||
# warnings by using asyncio.sleep(0)
|
||||
self.loop.run_until_complete(asyncio.sleep(0))
|
||||
self.assertEqual(sock.accept.call_count, backlog)
|
||||
|
||||
class SelectorTransportTests(test_utils.TestCase):
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Correct behavior of
|
||||
:func:`!asyncio.selector_events.BaseSelectorEventLoop._accept_connection`
|
||||
in handling :exc:`ConnectionAbortedError` in a loop. This improves
|
||||
performance on OpenBSD.
|
Loading…
Add table
Add a link
Reference in a new issue