From: Timofei <128279579+deadlovelll@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:08:32 +0000 (+0300) Subject: gh-151615: Avoid repeated reschedule in asyncio _accept_connection (#151616) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6081d166f191752c4dd17b5c6037bcf446c8dfb9;p=thirdparty%2FPython%2Fcpython.git gh-151615: Avoid repeated reschedule in asyncio _accept_connection (#151616) Co-authored-by: Kumar Aditya --- diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 4fa4dd5a8852..492dfcb19daf 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -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: diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 76ba39019e36..cf46c13fa5e1 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -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 index 000000000000..1d08dbacef1f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-18-00-39-58.gh-issue-151615.PBsCE1.rst @@ -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.