Kaydet (Commit) 3317a132 authored tarafından Guido van Rossum's avatar Guido van Rossum

asyncio: Pause accepting whenever accept() returns certain errors. Fixes asyncio issue #78.

üst 2b8fc303
"""Constants."""
# After the connection is lost, log warnings after this many write()s.
LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
# Seconds to wait before retrying accept().
ACCEPT_RETRY_DELAY = 1
......@@ -5,6 +5,7 @@ also includes support for signal handling, see the unix_events sub-module.
"""
import collections
import errno
import socket
try:
import ssl
......@@ -98,15 +99,23 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
try:
conn, addr = sock.accept()
conn.setblocking(False)
except (BlockingIOError, InterruptedError):
except (BlockingIOError, InterruptedError, ConnectionAbortedError):
pass # False alarm.
except Exception:
# Bad error. Stop serving.
self.remove_reader(sock.fileno())
sock.close()
except OSError as exc:
# There's nowhere to send the error, so just log it.
# TODO: Someone will want an error handler for this.
logger.exception('Accept failed')
if exc.errno in (errno.EMFILE, errno.ENFILE,
errno.ENOBUFS, errno.ENOMEM):
# Some platforms (e.g. Linux keep reporting the FD as
# ready, so we remove the read handler temporarily.
# We'll try again in a while.
logger.exception('Accept out of system resource (%s)', exc)
self.remove_reader(sock.fileno())
self.call_later(constants.ACCEPT_RETRY_DELAY,
self._start_serving,
protocol_factory, sock, ssl, server)
else:
raise # The event loop will catch, log and ignore it.
else:
if ssl:
self._make_ssl_transport(
......
"""Tests for base_events.py"""
import errno
import logging
import socket
import time
......@@ -8,6 +9,7 @@ import unittest.mock
from test.support import find_unused_port, IPV6_ENABLED
from asyncio import base_events
from asyncio import constants
from asyncio import events
from asyncio import futures
from asyncio import protocols
......@@ -585,11 +587,18 @@ class BaseEventLoopWithSelectorTests(unittest.TestCase):
def test_accept_connection_exception(self, m_log):
sock = unittest.mock.Mock()
sock.fileno.return_value = 10
sock.accept.side_effect = OSError()
sock.accept.side_effect = OSError(errno.EMFILE, 'Too many open files')
self.loop.remove_reader = unittest.mock.Mock()
self.loop.call_later = unittest.mock.Mock()
self.loop._accept_connection(MyProto, sock)
self.assertTrue(sock.close.called)
self.assertTrue(m_log.exception.called)
self.assertFalse(sock.close.called)
self.loop.remove_reader.assert_called_with(10)
self.loop.call_later.assert_called_with(constants.ACCEPT_RETRY_DELAY,
# self.loop._start_serving
unittest.mock.ANY,
MyProto, sock, None, None)
if __name__ == '__main__':
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment