From bec10c202e2484fd36070ae4be26ddc2bd7267d1 Mon Sep 17 00:00:00 2001 From: Jayashankar Padath Date: Tue, 29 May 2018 18:22:59 +0530 Subject: Avoid closing of web socket during the idle time "/subscribe" route of web socket is getting closed if it remains idle for more than 60 seconds. Once web socket get closed, it can't handle further event notifications. To avoid this, send a ping to wake it up during constant intervals. Resolves: Part of openbmc/openbmc#3102 Tested: Running GUI locally and verified the command line and web gui power on/off operations. Also could not see web socket getting closed during idle time. Change-Id: Ic3da0d30b99d1c3ac5ce4311204e6f6b09b8c1f0 Signed-off-by: Jayashankar Padath --- module/obmc/wsgi/apps/rest_dbus.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/module/obmc/wsgi/apps/rest_dbus.py b/module/obmc/wsgi/apps/rest_dbus.py index bf4fe7c..f92a67a 100644 --- a/module/obmc/wsgi/apps/rest_dbus.py +++ b/module/obmc/wsgi/apps/rest_dbus.py @@ -54,6 +54,7 @@ DBUS_INVALID_ARGS = 'org.freedesktop.DBus.Error.InvalidArgs' DBUS_TYPE_ERROR = 'org.freedesktop.DBus.Python.TypeError' DELETE_IFACE = 'xyz.openbmc_project.Object.Delete' SOFTWARE_PATH = '/xyz/openbmc_project/software' +WEBSOCKET_TIMEOUT = 45 _4034_msg = "The specified %s cannot be %s: '%s'" @@ -168,6 +169,22 @@ def convert_type(signature, value): return converted_container +def send_ws_ping(wsock, timeout) : + # Most webservers close websockets after 60 seconds of + # inactivity. Make sure to send a ping before that. + payload = "ping" + # the ping payload can be anything, the receiver has to just + # return the same back. + while True: + gevent.sleep(timeout) + try: + if wsock: + wsock.send_frame(payload, wsock.OPCODE_PING) + except Exception as e: + wsock.close() + return + + class UserInGroup: ''' Authorization plugin callback that checks that the user is logged in and a member of a group. ''' @@ -943,11 +960,11 @@ class EventHandler(RouteHandler): wsock = request.environ.get('wsgi.websocket') if not wsock: abort(400, 'Expected WebSocket request.') + ping_sender = Greenlet.spawn(send_ws_ping, wsock, WEBSOCKET_TIMEOUT) filters = wsock.receive() filters = json.loads(filters) notifier = EventNotifier(wsock, filters) - class HostConsoleHandler(RouteHandler): ''' Handles the /console route, for clients to be able read/write the host serial console. The way this is @@ -993,17 +1010,6 @@ class HostConsoleHandler(RouteHandler): wsock.close() return - def send_ping(self, wsock) : - # Most webservers close websockets after 60 seconds of - # inactivity. Make sure to send a ping before that. - timeout = 45 - payload = "ping" - # the ping payload can be anything, the receiver has to just - # return the same back. - while True: - gevent.sleep(timeout) - wsock.send_frame(payload, wsock.OPCODE_PING) - def do_get(self): wsock = request.environ.get('wsgi.websocket') if not wsock: @@ -1023,7 +1029,7 @@ class HostConsoleHandler(RouteHandler): wsock_reader = Greenlet.spawn(self.read_wsock, wsock, sock) sock_reader = Greenlet.spawn(self.read_sock, sock, wsock) - ping_sender = Greenlet.spawn(self.send_ping, wsock) + ping_sender = Greenlet.spawn(send_ws_ping, wsock, WEBSOCKET_TIMEOUT) gevent.joinall([wsock_reader, sock_reader, ping_sender]) -- cgit v1.2.1