Skip to content

Commit dfb7fce

Browse files
committed
gh-151615: Avoid repeated reschedule in asyncio _accept_connection
1 parent 32104a1 commit dfb7fce

3 files changed

Lines changed: 22 additions & 0 deletions

File tree

Lib/asyncio/selector_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def _accept_connection(
206206
protocol_factory, sock, sslcontext, server,
207207
backlog, ssl_handshake_timeout,
208208
ssl_shutdown_timeout, context)
209+
return
209210
else:
210211
raise # The event loop will catch, log and ignore it.
211212
else:

Lib/test/test_asyncio/test_selector_events.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for selector_events.py"""
22

33
import collections
4+
import errno
45
import selectors
56
import socket
67
import sys
@@ -402,6 +403,24 @@ def mock_sock_accept():
402403
self.loop.run_until_complete(asyncio.sleep(0))
403404
self.assertEqual(sock.accept.call_count, backlog + 1)
404405

406+
def test_accept_connection_reschedules_once_on_resource_error(self):
407+
# When accept() fails with a resource error (EMFILE), _accept_connection
408+
# re-runs the error branch backlog+1 times, logging and rescheduling
409+
# _start_serving once per iteration. With early return after first
410+
# exception we avoid this behaviour
411+
sock = mock.Mock()
412+
sock.accept.side_effect = OSError(errno.EMFILE, 'too many open files')
413+
414+
self.loop.call_exception_handler = mock.Mock()
415+
self.loop._remove_reader = mock.Mock()
416+
self.loop.call_later = mock.Mock()
417+
418+
self.loop._accept_connection(mock.Mock(), sock, backlog=100)
419+
420+
self.assertEqual(sock.accept.call_count, 1)
421+
self.assertEqual(self.loop.call_exception_handler.call_count, 1)
422+
self.assertEqual(self.loop.call_later.call_count, 1)
423+
405424
class SelectorTransportTests(test_utils.TestCase):
406425

407426
def setUp(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :mod:`asyncio` servers repeatedly logging and rescheduling on a single
2+
event loop iteration when ``accept()`` fails with a resource errors.

0 commit comments

Comments
 (0)