From f76b329cba4a934b351164c374dd062bbe9f5c4d Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 3 Dec 2018 19:14:22 +0800 Subject: [PATCH] Fix ConnectionResetError issues and switch to aiohttp version 3.4.4. Fixes #1474. --- gns3server/controller/compute.py | 1 + .../api/compute/notification_handler.py | 12 +++++------ .../handlers/api/compute/project_handler.py | 2 -- .../api/controller/notification_handler.py | 20 +++++++++---------- .../api/controller/project_handler.py | 19 ++++++++---------- gns3server/web/route.py | 1 + gns3server/web/web_server.py | 5 ++++- requirements.txt | 4 ++-- 8 files changed, 31 insertions(+), 33 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 8a4be5da..31c59ce1 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -449,6 +449,7 @@ class Compute: if action == "ping": self._cpu_usage_percent = event["cpu_usage_percent"] self._memory_usage_percent = event["memory_usage_percent"] + #FIXME: slow down number of compute events self._controller.notification.controller_emit("compute.updated", self.__json__()) else: await self._controller.notification.dispatch(action, event, compute_id=self.id) diff --git a/gns3server/handlers/api/compute/notification_handler.py b/gns3server/handlers/api/compute/notification_handler.py index 7446a6ce..81cf9d0e 100644 --- a/gns3server/handlers/api/compute/notification_handler.py +++ b/gns3server/handlers/api/compute/notification_handler.py @@ -45,14 +45,14 @@ class NotificationHandler: request.app['websockets'].add(ws) asyncio.ensure_future(process_websocket(ws)) with notifications.queue() as queue: - while True: - try: + try: + while True: notification = await queue.get_json(1) if ws.closed: break await ws.send_str(notification) - except asyncio.futures.CancelledError: - break - finally: - request.app['websockets'].discard(ws) + finally: + if not ws.closed: + await ws.close() + request.app['websockets'].discard(ws) return ws diff --git a/gns3server/handlers/api/compute/project_handler.py b/gns3server/handlers/api/compute/project_handler.py index fc207967..c10c1c49 100644 --- a/gns3server/handlers/api/compute/project_handler.py +++ b/gns3server/handlers/api/compute/project_handler.py @@ -191,8 +191,6 @@ class ProjectHandler: msg = json.dumps({"action": action, "event": msg}, sort_keys=True) log.debug("Send notification: %s", msg) await response.write(("{}\n".format(msg)).encode("utf-8")) - except asyncio.futures.CancelledError as e: - break except asyncio.futures.TimeoutError: await response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8")) project.stop_listen_queue(queue) diff --git a/gns3server/handlers/api/controller/notification_handler.py b/gns3server/handlers/api/controller/notification_handler.py index 2d2cc14d..5e26fb27 100644 --- a/gns3server/handlers/api/controller/notification_handler.py +++ b/gns3server/handlers/api/controller/notification_handler.py @@ -50,11 +50,8 @@ class NotificationHandler: await response.prepare(request) with controller.notification.controller_queue() as queue: while True: - try: - msg = await queue.get_json(5) - await response.write(("{}\n".format(msg)).encode("utf-8")) - except asyncio.futures.CancelledError: - break + msg = await queue.get_json(5) + await response.write(("{}\n".format(msg)).encode("utf-8")) @Route.get( r"/notifications/ws", @@ -71,14 +68,15 @@ class NotificationHandler: request.app['websockets'].add(ws) asyncio.ensure_future(process_websocket(ws)) with controller.notification.controller_queue() as queue: - while True: - try: + try: + while True: notification = await queue.get_json(5) if ws.closed: break await ws.send_str(notification) - except asyncio.futures.CancelledError: - break - finally: - request.app['websockets'].discard(ws) + finally: + if not ws.closed: + await ws.close() + request.app['websockets'].discard(ws) + return ws diff --git a/gns3server/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index ea22a00b..265fb96f 100644 --- a/gns3server/handlers/api/controller/project_handler.py +++ b/gns3server/handlers/api/controller/project_handler.py @@ -229,11 +229,8 @@ class ProjectHandler: await response.prepare(request) with controller.notification.project_queue(project) as queue: while True: - try: - msg = await queue.get_json(5) - await response.write(("{}\n".format(msg)).encode("utf-8")) - except asyncio.futures.CancelledError as e: - break + msg = await queue.get_json(5) + await response.write(("{}\n".format(msg)).encode("utf-8")) if project.auto_close: # To avoid trouble with client connecting disconnecting we sleep few seconds before checking @@ -263,16 +260,16 @@ class ProjectHandler: request.app['websockets'].add(ws) asyncio.ensure_future(process_websocket(ws)) with controller.notification.project_queue(project) as queue: - while True: - try: + try: + while True: notification = await queue.get_json(5) if ws.closed: break await ws.send_str(notification) - except asyncio.futures.CancelledError: - break - finally: - request.app['websockets'].discard(ws) + finally: + if not ws.closed: + await ws.close() + request.app['websockets'].discard(ws) if project.auto_close: # To avoid trouble with client connecting disconnecting we sleep few seconds before checking diff --git a/gns3server/web/route.py b/gns3server/web/route.py index 9e7d0eee..c2724485 100644 --- a/gns3server/web/route.py +++ b/gns3server/web/route.py @@ -221,6 +221,7 @@ class Route(object): response = Response(request=request, route=route) response.set_status(408) response.json({"message": "Request canceled", "status": 408}) + raise # must raise to let aiohttp know the connection has been closed except aiohttp.ClientError: log.warning("Client error") response = Response(request=request, route=route) diff --git a/gns3server/web/web_server.py b/gns3server/web/web_server.py index 3fb3fdec..9b7c6e19 100644 --- a/gns3server/web/web_server.py +++ b/gns3server/web/web_server.py @@ -102,7 +102,10 @@ class WebServer: return # close websocket connections - for ws in set(self._app['websockets']): + websocket_connections = set(self._app['websockets']) + if websocket_connections: + log.info("Closing {} websocket connections...".format(len(websocket_connections))) + for ws in websocket_connections: await ws.close(code=aiohttp.WSCloseCode.GOING_AWAY, message='Server shutdown') if self._server: diff --git a/requirements.txt b/requirements.txt index d93bc735..0bec034e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ jsonschema>=2.4.0 -aiohttp==3.2.1 +aiohttp==3.4.4 aiohttp-cors==0.7.0 Jinja2>=2.7.3 raven>=5.23.0 @@ -7,4 +7,4 @@ psutil>=3.0.0 zipstream>=1.1.4 prompt-toolkit==1.0.15 async-timeout==3.0.1 -distro>=1.3.0 \ No newline at end of file +distro>=1.3.0