Browse Source

Prevent pubsub managers from ever crashing

Fixes #1262
pull/1298/head
Miguel Grinberg 1 year ago
parent
commit
12134bd5c5
Failed to extract signature
  1. 12
      src/socketio/async_pubsub_manager.py
  2. 77
      src/socketio/pubsub_manager.py
  3. 1
      tests/async/test_pubsub_manager.py

12
src/socketio/async_pubsub_manager.py

@ -230,11 +230,13 @@ class AsyncPubSubManager(AsyncManager):
await self._handle_close_room(data)
except asyncio.CancelledError:
raise # let the outer try/except handle it
except:
except Exception:
self.server.logger.exception(
'Unknown error in pubsub listening task')
'Handler error in pubsub listening thread')
self.server.logger.error('pubsub listen() exited unexpectedly')
break # loop should never exit except in unit tests!
except asyncio.CancelledError: # pragma: no cover
break
except: # pragma: no cover
import traceback
traceback.print_exc()
except Exception: # pragma: no cover
self.server.logger.exception('Unexpected Error in pubsub '
'listening thread')

77
src/socketio/pubsub_manager.py

@ -188,38 +188,45 @@ class PubSubManager(Manager):
namespace=message.get('namespace'))
def _thread(self):
for message in self._listen():
data = None
if isinstance(message, dict):
data = message
else:
if isinstance(message, bytes): # pragma: no cover
try:
data = pickle.loads(message)
except:
pass
if data is None:
try:
data = json.loads(message)
except:
pass
if data and 'method' in data:
self._get_logger().debug('pubsub message: {}'.format(
data['method']))
try:
if data['method'] == 'callback':
self._handle_callback(data)
elif data.get('host_id') != self.host_id:
if data['method'] == 'emit':
self._handle_emit(data)
elif data['method'] == 'disconnect':
self._handle_disconnect(data)
elif data['method'] == 'enter_room':
self._handle_enter_room(data)
elif data['method'] == 'leave_room':
self._handle_leave_room(data)
elif data['method'] == 'close_room':
self._handle_close_room(data)
except:
self.server.logger.exception(
'Unknown error in pubsub listening thread')
while True:
try:
for message in self._listen():
data = None
if isinstance(message, dict):
data = message
else:
if isinstance(message, bytes): # pragma: no cover
try:
data = pickle.loads(message)
except:
pass
if data is None:
try:
data = json.loads(message)
except:
pass
if data and 'method' in data:
self._get_logger().debug('pubsub message: {}'.format(
data['method']))
try:
if data['method'] == 'callback':
self._handle_callback(data)
elif data.get('host_id') != self.host_id:
if data['method'] == 'emit':
self._handle_emit(data)
elif data['method'] == 'disconnect':
self._handle_disconnect(data)
elif data['method'] == 'enter_room':
self._handle_enter_room(data)
elif data['method'] == 'leave_room':
self._handle_leave_room(data)
elif data['method'] == 'close_room':
self._handle_close_room(data)
except Exception:
self.server.logger.exception(
'Handler error in pubsub listening thread')
self.server.logger.error('pubsub listen() exited unexpectedly')
break # loop should never exit except in unit tests!
except Exception: # pragma: no cover
self.server.logger.exception('Unexpected Error in pubsub '
'listening thread')

1
tests/async/test_pubsub_manager.py

@ -541,7 +541,6 @@ class TestAsyncPubSubManager(unittest.TestCase):
'host_id': host_id}
yield pickle.dumps({'method': 'close_room', 'value': 'baz',
'host_id': host_id})
raise asyncio.CancelledError() # force the thread to exit
self.pm._listen = messages
_run(self.pm._thread())

Loading…
Cancel
Save