Browse Source

async_handlers option for asyncio servers

pull/117/merge
Miguel Grinberg 8 years ago
parent
commit
93f70dc9e1
No known key found for this signature in database GPG Key ID: 36848B262DF5F06C
  1. 5
      socketio/asyncio_manager.py
  2. 15
      socketio/asyncio_server.py
  3. 19
      tests/test_asyncio_server.py

5
socketio/asyncio_manager.py

@ -23,8 +23,9 @@ class AsyncManager(BaseManager):
id = None id = None
tasks.append(self.server._emit_internal(sid, event, data, tasks.append(self.server._emit_internal(sid, event, data,
namespace, id)) namespace, id))
if tasks != []: if tasks == []: # pragma: no cover
await asyncio.wait(tasks) return
await asyncio.wait(tasks)
async def close_room(self, room, namespace): async def close_room(self, room, namespace):
"""Remove all participants from a room. """Remove all participants from a room.

15
socketio/asyncio_server.py

@ -24,6 +24,9 @@ class AsyncServer(server.Server):
packets. Custom json modules must have ``dumps`` and ``loads`` packets. Custom json modules must have ``dumps`` and ``loads``
functions that are compatible with the standard library functions that are compatible with the standard library
versions. versions.
:param async_handlers: If set to ``True``, event handlers are executed in
separate threads. To run handlers synchronously,
set to ``False``. The default is ``False``.
:param kwargs: Connection parameters for the underlying Engine.IO server. :param kwargs: Connection parameters for the underlying Engine.IO server.
The Engine.IO configuration supports the following settings: The Engine.IO configuration supports the following settings:
@ -55,11 +58,13 @@ class AsyncServer(server.Server):
a logger object to use. To disable logging set to a logger object to use. To disable logging set to
``False``. ``False``.
""" """
def __init__(self, client_manager=None, logger=False, json=None, **kwargs): def __init__(self, client_manager=None, logger=False, json=None,
async_handlers=False, **kwargs):
if client_manager is None: if client_manager is None:
client_manager = asyncio_manager.AsyncManager() client_manager = asyncio_manager.AsyncManager()
super().__init__(client_manager=client_manager, logger=logger, super().__init__(client_manager=client_manager, logger=logger,
binary=False, json=json, **kwargs) binary=False, json=json,
async_handlers=async_handlers, **kwargs)
def is_asyncio_based(self): def is_asyncio_based(self):
return True return True
@ -280,7 +285,11 @@ class AsyncServer(server.Server):
namespace = namespace or '/' namespace = namespace or '/'
self.logger.info('received event "%s" from %s [%s]', data[0], sid, self.logger.info('received event "%s" from %s [%s]', data[0], sid,
namespace) namespace)
await self._handle_event_internal(self, sid, data, namespace, id) if self.async_handlers:
self.start_background_task(self._handle_event_internal, self, sid,
data, namespace, id)
else:
await self._handle_event_internal(self, sid, data, namespace, id)
async def _handle_event_internal(self, server, sid, data, namespace, id): async def _handle_event_internal(self, server, sid, data, namespace, id):
r = await server._trigger_event(data[0], namespace, sid, *data[1:]) r = await server._trigger_event(data[0], namespace, sid, *data[1:])

19
tests/test_asyncio_server.py

@ -56,14 +56,15 @@ class TestAsyncServer(unittest.TestCase):
def test_create(self, eio): def test_create(self, eio):
eio.return_value.handle_request = AsyncMock() eio.return_value.handle_request = AsyncMock()
mgr = self._get_mock_manager() mgr = self._get_mock_manager()
s = asyncio_server.AsyncServer(client_manager=mgr, foo='bar') s = asyncio_server.AsyncServer(client_manager=mgr,
async_handlers=True, foo='bar')
_run(s.handle_request({})) _run(s.handle_request({}))
_run(s.handle_request({})) _run(s.handle_request({}))
eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False}) eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False})
self.assertEqual(s.manager, mgr) self.assertEqual(s.manager, mgr)
self.assertEqual(s.eio.on.call_count, 3) self.assertEqual(s.eio.on.call_count, 3)
self.assertEqual(s.binary, False) self.assertEqual(s.binary, False)
self.assertEqual(s.async_handlers, False) self.assertEqual(s.async_handlers, True)
def test_attach(self, eio): def test_attach(self, eio):
s = asyncio_server.AsyncServer() s = asyncio_server.AsyncServer()
@ -581,12 +582,18 @@ class TestAsyncServer(unittest.TestCase):
# restore the default JSON module # restore the default JSON module
packet.Packet.json = json packet.Packet.json = json
def test_async_handlers(self, eio):
s = asyncio_server.AsyncServer(async_handlers=True)
_run(s._handle_eio_message('123', '2["my message","a","b","c"]'))
s.eio.start_background_task.assert_called_once_with(
s._handle_event_internal, s, '123', ['my message', 'a', 'b', 'c'],
'/', None)
def test_start_background_task(self, eio): def test_start_background_task(self, eio):
eio.return_value.start_background_task = AsyncMock()
s = asyncio_server.AsyncServer() s = asyncio_server.AsyncServer()
_run(s.start_background_task('foo', 'bar', baz='baz')) s.start_background_task('foo', 'bar', baz='baz')
s.eio.start_background_task.mock.assert_called_once_with('foo', 'bar', s.eio.start_background_task.assert_called_once_with('foo', 'bar',
baz='baz') baz='baz')
def test_sleep(self, eio): def test_sleep(self, eio):
eio.return_value.sleep = AsyncMock() eio.return_value.sleep = AsyncMock()

Loading…
Cancel
Save