Keep-alive requests stay open if communicating
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| import asyncio | ||||
| from functools import partial | ||||
| from inspect import isawaitable | ||||
| from signal import SIGINT, SIGTERM | ||||
|  | ||||
| @@ -16,7 +17,6 @@ from .request import Request | ||||
| class Signal: | ||||
|     stopped = False | ||||
|  | ||||
|  | ||||
| class HttpProtocol(asyncio.Protocol): | ||||
|     __slots__ = ( | ||||
|         # event loop, connection | ||||
| @@ -26,7 +26,7 @@ class HttpProtocol(asyncio.Protocol): | ||||
|         # request config | ||||
|         'request_handler', 'request_timeout', 'request_max_size', | ||||
|         # connection management | ||||
|         '_total_request_size', '_timeout_handler') | ||||
|         '_total_request_size', '_timeout_handler', '_last_communication_time') | ||||
|  | ||||
|     def __init__(self, *, loop, request_handler, signal=Signal(), | ||||
|                  connections={}, request_timeout=60, | ||||
| @@ -44,6 +44,7 @@ class HttpProtocol(asyncio.Protocol): | ||||
|         self.request_max_size = request_max_size | ||||
|         self._total_request_size = 0 | ||||
|         self._timeout_handler = None | ||||
|         self._last_request_time = None | ||||
|  | ||||
|         # -------------------------------------------- # | ||||
|  | ||||
| @@ -55,6 +56,7 @@ class HttpProtocol(asyncio.Protocol): | ||||
|         self._timeout_handler = self.loop.call_later( | ||||
|             self.request_timeout, self.connection_timeout) | ||||
|         self.transport = transport | ||||
|         self._last_request_time = current_time | ||||
|  | ||||
|     def connection_lost(self, exc): | ||||
|         del self.connections[self] | ||||
| @@ -62,6 +64,13 @@ class HttpProtocol(asyncio.Protocol): | ||||
|         self.cleanup() | ||||
|  | ||||
|     def connection_timeout(self): | ||||
|         # Check if | ||||
|         time_elapsed = current_time - self._last_request_time | ||||
|         if time_elapsed < self.request_timeout: | ||||
|             time_left = self.request_timeout - time_elapsed | ||||
|             self._timeout_handler = \ | ||||
|                 self.loop.call_later(time_left, self.connection_timeout) | ||||
|         else: | ||||
|             self.bail_out("Request timed out, connection closed") | ||||
|  | ||||
|         # -------------------------------------------- # | ||||
| @@ -133,13 +142,15 @@ class HttpProtocol(asyncio.Protocol): | ||||
|             if not keep_alive: | ||||
|                 self.transport.close() | ||||
|             else: | ||||
|                 # Record that we received data | ||||
|                 self._last_request_time = current_time | ||||
|                 self.cleanup() | ||||
|         except Exception as e: | ||||
|             self.bail_out( | ||||
|                 "Writing request failed, connection closed {}".format(e)) | ||||
|  | ||||
|     def bail_out(self, message): | ||||
|         log.error(message) | ||||
|         log.debug(message) | ||||
|         self.transport.close() | ||||
|  | ||||
|     def cleanup(self): | ||||
| @@ -159,6 +170,19 @@ class HttpProtocol(asyncio.Protocol): | ||||
|             return True | ||||
|         return False | ||||
|  | ||||
| # Keep check on the current time | ||||
| current_time = None | ||||
| def update_current_time(loop): | ||||
|     """ | ||||
|     Caches the current time, since it is needed | ||||
|     at the end of every keep-alive request to update the request timeout time | ||||
|     :param loop: | ||||
|     :return: | ||||
|     """ | ||||
|     global current_time | ||||
|     current_time = loop.time() | ||||
|     loop.call_later(0.5, partial(update_current_time, loop)) | ||||
|  | ||||
|  | ||||
| def trigger_events(events, loop): | ||||
|     """ | ||||
| @@ -173,7 +197,6 @@ def trigger_events(events, loop): | ||||
|             if isawaitable(result): | ||||
|                 loop.run_until_complete(result) | ||||
|  | ||||
|  | ||||
| def serve(host, port, request_handler, before_start=None, after_start=None, | ||||
|           before_stop=None, after_stop=None, | ||||
|           debug=False, request_timeout=60, sock=None, | ||||
| @@ -214,6 +237,10 @@ def serve(host, port, request_handler, before_start=None, after_start=None, | ||||
|         request_max_size=request_max_size, | ||||
|     ), host, port, reuse_port=reuse_port, sock=sock) | ||||
|  | ||||
|     # Instead of pulling time at the end of every request, | ||||
|     # pull it once per minute | ||||
|     loop.call_soon(partial(update_current_time, loop)) | ||||
|  | ||||
|     try: | ||||
|         http_server = loop.run_until_complete(server_coroutine) | ||||
|     except Exception: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Channel Cat
					Channel Cat