Skip to content

Commit

Permalink
Merge pull request #401 from MichaIng/patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
webknjaz authored Jan 3, 2022
2 parents 5a765e6 + b67e931 commit fe8dd50
Showing 1 changed file with 35 additions and 7 deletions.
42 changes: 35 additions & 7 deletions cheroot/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from . import errors
from ._compat import selectors
from ._compat import suppress
from ._compat import IS_WINDOWS
from .makefile import MakeFile

import six
Expand Down Expand Up @@ -152,17 +153,18 @@ def put(self, conn):
conn.socket.fileno(), selectors.EVENT_READ, data=conn,
)

def _expire(self):
"""Expire least recently used connections.
def _expire(self, threshold):
r"""Expire least recently used connections.
This happens if there are either too many open connections, or if the
connections have been timed out.
:param threshold: Connections that have not been used within this \
duration (in seconds), are considered expired and \
are closed and removed.
:type threshold: float
This should be called periodically.
"""
# find any connections still registered with the selector
# that have not been active recently enough.
threshold = time.time() - self.server.timeout
timed_out_connections = [
(sock_fd, conn)
for (sock_fd, conn) in self._selector.connections
Expand Down Expand Up @@ -203,11 +205,37 @@ def run(self, expiration_interval):
self._serving = False

def _run(self, expiration_interval):
r"""Run connection handler loop until stop was requested.
:param expiration_interval: Interval, in seconds, at which \
connections will be checked for \
expiration.
:type expiration_interval: float
Use ``expiration_interval`` as ``select()`` timeout
to assure expired connections are closed in time.
On Windows cap the timeout to 0.05 seconds
as ``select()`` does not return when a socket is ready.
"""
last_expiration_check = time.time()
if IS_WINDOWS:
# 0.05 seconds are used as an empirically obtained balance between
# max connection delay and idle system load. Benchmarks show a
# mean processing time per connection of ~0.03 seconds on Linux
# and with 0.01 seconds timeout on Windows:
# https://github.com/cherrypy/cheroot/pull/352
# While this highly depends on system and hardware, 0.05 seconds
# max delay should hence usually not significantly increase the
# mean time/delay per connection, but significantly reduce idle
# system load by reducing socket loops to 1/5 with 0.01 seconds.
select_timeout = min(expiration_interval, 0.05)
else:
select_timeout = expiration_interval

while not self._stop_requested:
try:
active_list = self._selector.select(timeout=0.01)
active_list = self._selector.select(timeout=select_timeout)
except OSError:
self._remove_invalid_sockets()
continue
Expand All @@ -226,7 +254,7 @@ def _run(self, expiration_interval):

now = time.time()
if (now - last_expiration_check) > expiration_interval:
self._expire()
self._expire(threshold=now - self.server.timeout)
last_expiration_check = now

def _remove_invalid_sockets(self):
Expand Down

0 comments on commit fe8dd50

Please sign in to comment.