]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-151615: Avoid repeated reschedule in asyncio _accept_connection (#151616)
authorTimofei <128279579+deadlovelll@users.noreply.github.com>
Sun, 12 Jul 2026 10:08:32 +0000 (13:08 +0300)
committerGitHub <noreply@github.com>
Sun, 12 Jul 2026 10:08:32 +0000 (15:38 +0530)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Lib/asyncio/selector_events.py
Lib/test/test_asyncio/test_selector_events.py
Misc/NEWS.d/next/Library/2026-06-18-00-39-58.gh-issue-151615.PBsCE1.rst [new file with mode: 0644]

index 4fa4dd5a885236e5cc50fee9b2cf92efdebd4e52..492dfcb19dafe2274072860398533a14ec8bfdf0 100644 (file)
@@ -206,6 +206,7 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
                                     protocol_factory, sock, sslcontext, server,
                                     backlog, ssl_handshake_timeout,
                                     ssl_shutdown_timeout, context)
+                    return
                 else:
                     raise  # The event loop will catch, log and ignore it.
             else:
index 76ba39019e36631c2d14a817efec596b9cc5eabd..cf46c13fa5e1f39b770c7ee057ed6a09897ea800 100644 (file)
@@ -1,6 +1,7 @@
 """Tests for selector_events.py"""
 
 import collections
+import errno
 import selectors
 import socket
 import sys
@@ -402,6 +403,24 @@ class BaseSelectorEventLoopTests(test_utils.TestCase):
         self.loop.run_until_complete(asyncio.sleep(0))
         self.assertEqual(sock.accept.call_count, backlog + 1)
 
+    def test_accept_connection_reschedules_once_on_resource_error(self):
+        # When accept() fails with a resource error (EMFILE), _accept_connection
+        # re-runs the error branch backlog+1 times, logging and rescheduling
+        # _start_serving once per iteration. With early return after first
+        # exception we avoid this behaviour
+        sock = mock.Mock()
+        sock.accept.side_effect = OSError(errno.EMFILE, 'too many open files')
+
+        self.loop.call_exception_handler = mock.Mock()
+        self.loop._remove_reader = mock.Mock()
+        self.loop.call_later = mock.Mock()
+
+        self.loop._accept_connection(mock.Mock(), sock, backlog=100)
+
+        self.assertEqual(sock.accept.call_count, 1)
+        self.assertEqual(self.loop.call_exception_handler.call_count, 1)
+        self.assertEqual(self.loop.call_later.call_count, 1)
+
 class SelectorTransportTests(test_utils.TestCase):
 
     def setUp(self):
diff --git a/Misc/NEWS.d/next/Library/2026-06-18-00-39-58.gh-issue-151615.PBsCE1.rst b/Misc/NEWS.d/next/Library/2026-06-18-00-39-58.gh-issue-151615.PBsCE1.rst
new file mode 100644 (file)
index 0000000..1d08dba
--- /dev/null
@@ -0,0 +1,2 @@
+Fix :mod:`asyncio` servers repeatedly logging and rescheduling on a single
+event loop iteration when ``accept()`` fails with a resource errors.