Skip to content

Commit 2d39058

Browse files
add async_handlers option to server
1 parent 214abc8 commit 2d39058

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

socketio/server.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class Server(object):
3030
packets. Custom json modules must have ``dumps`` and ``loads``
3131
functions that are compatible with the standard library
3232
versions.
33+
:param async_handlers: If set to ``True``, event handlers are executed in
34+
separate threads. To run handlers synchronously,
35+
set to ``False``. The default is ``False``.
3336
:param kwargs: Connection parameters for the underlying Engine.IO server.
3437
3538
The Engine.IO configuration supports the following settings:
@@ -62,14 +65,15 @@ class Server(object):
6265
``False``.
6366
"""
6467
def __init__(self, client_manager=None, logger=False, binary=False,
65-
json=None, **kwargs):
68+
json=None, async_handlers=False, **kwargs):
6669
engineio_options = kwargs
6770
engineio_logger = engineio_options.pop('engineio_logger', None)
6871
if engineio_logger is not None:
6972
engineio_options['logger'] = engineio_logger
7073
if json is not None:
7174
packet.Packet.json = json
7275
engineio_options['json'] = json
76+
engineio_options['async_handlers'] = False
7377
self.eio = engineio.Server(**engineio_options)
7478
self.eio.on('connect', self._handle_eio_connect)
7579
self.eio.on('message', self._handle_eio_message)
@@ -99,6 +103,8 @@ def __init__(self, client_manager=None, logger=False, binary=False,
99103
self.manager = client_manager
100104
self.manager_initialized = False
101105

106+
self.async_handlers = async_handlers
107+
102108
self.async_mode = self.eio.async_mode
103109

104110
def on(self, event, handler=None, namespace=None):
@@ -412,7 +418,14 @@ def _handle_event(self, sid, namespace, id, data):
412418
namespace = namespace or '/'
413419
self.logger.info('received event "%s" from %s [%s]', data[0], sid,
414420
namespace)
415-
r = self._trigger_event(data[0], namespace, sid, *data[1:])
421+
if self.async_handlers:
422+
self.start_background_task(self._handle_event_internal, self, sid,
423+
data, namespace, id)
424+
else:
425+
self._handle_event_internal(self, sid, data, namespace, id)
426+
427+
def _handle_event_internal(self, server, sid, data, namespace, id):
428+
r = server._trigger_event(data[0], namespace, sid, *data[1:])
416429
if id is not None:
417430
# send ACK packet with the response returned by the handler
418431
# tuples are expanded as multiple arguments
@@ -426,10 +439,10 @@ def _handle_event(self, sid, namespace, id, data):
426439
binary = False # pragma: nocover
427440
else:
428441
binary = None
429-
self._send_packet(sid, packet.Packet(packet.ACK,
430-
namespace=namespace,
431-
id=id, data=data,
432-
binary=binary))
442+
server._send_packet(sid, packet.Packet(packet.ACK,
443+
namespace=namespace,
444+
id=id, data=data,
445+
binary=binary))
433446

434447
def _handle_ack(self, sid, namespace, id, data):
435448
"""Handle ACK packets from the client."""

tests/test_server.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ def tearDown(self):
2121

2222
def test_create(self, eio):
2323
mgr = mock.MagicMock()
24-
s = server.Server(client_manager=mgr, binary=True, foo='bar')
24+
s = server.Server(client_manager=mgr, binary=True,
25+
async_handlers=True, foo='bar')
2526
s.handle_request({}, None)
2627
s.handle_request({}, None)
27-
eio.assert_called_once_with(**{'foo': 'bar'})
28+
eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False})
2829
self.assertEqual(s.manager, mgr)
2930
self.assertEqual(s.eio.on.call_count, 3)
3031
self.assertEqual(s.binary, True)
32+
self.assertEqual(s.async_handlers, True)
3133
self.assertEqual(mgr.initialize.call_count, 1)
3234

3335
def test_on_event(self, eio):
@@ -428,6 +430,8 @@ class Dummy(object):
428430
self.assertRaises(ValueError, s.register_namespace, 123)
429431
self.assertRaises(ValueError, s.register_namespace, Dummy)
430432
self.assertRaises(ValueError, s.register_namespace, Dummy())
433+
self.assertRaises(ValueError, s.register_namespace,
434+
namespace.Namespace)
431435

432436
def test_logger(self, eio):
433437
s = server.Server(logger=False)
@@ -444,7 +448,8 @@ def test_logger(self, eio):
444448

445449
def test_engineio_logger(self, eio):
446450
server.Server(engineio_logger='foo')
447-
eio.assert_called_once_with(**{'logger': 'foo'})
451+
eio.assert_called_once_with(**{'logger': 'foo',
452+
'async_handlers': False})
448453

449454
def test_custom_json(self, eio):
450455
# Warning: this test cannot run in parallel with other tests, as it
@@ -460,7 +465,8 @@ def loads(*args, **kwargs):
460465
return '+++ decoded +++'
461466

462467
server.Server(json=CustomJSON)
463-
eio.assert_called_once_with(**{'json': CustomJSON})
468+
eio.assert_called_once_with(**{'json': CustomJSON,
469+
'async_handlers': False})
464470

465471
pkt = packet.Packet(packet_type=packet.EVENT,
466472
data={six.text_type('foo'): six.text_type('bar')})
@@ -471,6 +477,13 @@ def loads(*args, **kwargs):
471477
# restore the default JSON module
472478
packet.Packet.json = json
473479

480+
def test_async_handlers(self, eio):
481+
s = server.Server(async_handlers=True)
482+
s._handle_eio_message('123', '2["my message","a","b","c"]')
483+
s.eio.start_background_task.assert_called_once_with(
484+
s._handle_event_internal, s, '123', ['my message', 'a', 'b', 'c'],
485+
'/', None)
486+
474487
def test_start_background_task(self, eio):
475488
s = server.Server()
476489
s.start_background_task('foo', 'bar', baz='baz')

0 commit comments

Comments
 (0)