Skip to content

Commit 57756e3

Browse files
Add write_only argument to Kombu and Redis manager classes
1 parent 0e47a75 commit 57756e3

File tree

5 files changed

+53
-21
lines changed

5 files changed

+53
-21
lines changed

docs/index.rst

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,11 @@ type of installation, each server processes owns the connections to a subset
233233
of the clients. To make broadcasting work in this environment, the servers
234234
communicate with each other through the message queue.
235235

236-
The message queue service needs to be installed and configured separately. By
237-
default, the server uses `Kombu <http://kombu.readthedocs.org/en/latest/>`_
238-
to access the message queue, so any message queue supported by this package
239-
can be used. Kombu can be installed with pip::
236+
The message queue service needs to be installed and configured separately. One
237+
of the options offered by this package is to use
238+
`Kombu <http://kombu.readthedocs.org/en/latest/>`_ to access the message
239+
queue, which means that any message queue supported by this package can be
240+
used. Kombu can be installed with pip::
240241

241242
pip install kombu
242243

@@ -252,29 +253,40 @@ To configure a Socket.IO server to connect to a message queue, the
252253
following example instructs the server to connect to a Redis service running
253254
on the same host and on the default port::
254255

255-
redis = socketio.KombuManager('redis://')
256-
sio = socketio.Server(client_manager=redis)
256+
mgr = socketio.KombuManager('redis://')
257+
sio = socketio.Server(client_manager=mgr)
257258

258259
For a RabbitMQ queue also running on the local server with default
259260
credentials, the configuration is as follows::
260261

261-
amqp = socketio.KombuManager('amqp://')
262-
sio = socketio.Server(client_manager=amqp)
262+
mgr = socketio.KombuManager('amqp://')
263+
sio = socketio.Server(client_manager=mgr)
263264

264-
The arguments passed to the ``KombuManager`` constructor are passed directly
265-
to Kombu's `Connection object
265+
The URL passed to the ``KombuManager`` constructor is passed directly to
266+
Kombu's `Connection object
266267
<http://kombu.readthedocs.org/en/latest/userguide/connections.html>`_, so
267268
the Kombu documentation should be consulted for information on how to
268269
connect to the message queue appropriately.
269270

271+
If the use of Kombu is not desired, native Redis support is also offered
272+
through the ``RedisManager`` class. This class takes the same arguments as
273+
``KombuManager``, but connects directly to a Redis store using the queue's
274+
pub/sub functionality::
275+
276+
277+
mgr = socketio.RedisManager('redis://')
278+
sio = socketio.Server(client_manager=mgr)
279+
270280
If multiple Sokcet.IO servers are connected to a message queue, they
271281
automatically communicate with each other and manage a combined client list,
272282
without any need for additional configuration. To have a process other than
273-
the server connect to the queue to emit a message, the same ``KombuManager``
274-
class can be used as standalone object. For example::
283+
a server connect to the queue to emit a message, the same ``KombuManager``
284+
and ``RedisManager`` classes can be used as standalone object. In this case,
285+
the ``write_only`` argument should be set to ``True`` to disable the creation
286+
of a listening thread. For example::
275287

276-
# connect to the redis queue
277-
redis = socketio.KombuManager('redis://localhost:6379/')
288+
# connect to the redis queue through Kombu
289+
redis = socketio.KombuManager('redis://', write_only=True)
278290
279291
# emit an event
280292
redis.emit('my event', data={'foo': 'bar'}, room='my room')

socketio/kombu_manager.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,23 @@ class KombuManager(PubSubManager): # pragma: no cover
3131
connection URLs.
3232
:param channel: The channel name on which the server sends and receives
3333
notifications. Must be the same in all the servers.
34+
:param write_only: If set ot ``True``, only initialize to emit events. The
35+
default of ``False`` initializes the class for emitting
36+
and receiving.
3437
"""
3538
name = 'kombu'
3639

3740
def __init__(self, url='amqp://guest:guest@localhost:5672//',
38-
channel='socketio'):
41+
channel='socketio', write_only=False):
3942
if kombu is None:
4043
raise RuntimeError('Kombu package is not installed '
4144
'(Run "pip install kombu" in your '
4245
'virtualenv).')
4346
self.kombu = kombu.Connection(url)
4447
self.exchange = kombu.Exchange(channel, type='fanout', durable=False)
4548
self.queue = kombu.Queue(str(uuid.uuid4()), self.exchange)
46-
super(KombuManager, self).__init__(channel=channel)
49+
super(KombuManager, self).__init__(channel=channel,
50+
write_only=write_only)
4751

4852
def _publish(self, data):
4953
with self.kombu.SimpleQueue(self.queue) as queue:

socketio/pubsub_manager.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ class PubSubManager(BaseManager):
2424
"""
2525
name = 'pubsub'
2626

27-
def __init__(self, channel='socketio'):
27+
def __init__(self, channel='socketio', write_only=False):
2828
super(PubSubManager, self).__init__()
2929
self.channel = channel
30+
self.write_only = write_only
3031
self.host_id = uuid.uuid4().hex
3132

3233
def initialize(self, server):
3334
super(PubSubManager, self).initialize(server)
34-
self.thread = self.server.start_background_task(self._thread)
35+
if not self.write_only:
36+
self.thread = self.server.start_background_task(self._thread)
3537
self.server.logger.info(self.name + ' backend initialized.')
3638

3739
def emit(self, event, data, namespace=None, room=None, skip_sid=None,

socketio/redis_manager.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,26 @@ class RedisManager(PubSubManager): # pragma: no cover
2222
url = 'redis://hostname:port/0'
2323
server = socketio.Server(client_manager=socketio.RedisManager(url))
2424
25-
:param url: The connection URL for the Redis server.
25+
:param url: The connection URL for the Redis server. For a default Redis
26+
store running on the same host, use ``redis://``.
2627
:param channel: The channel name on which the server sends and receives
2728
notifications. Must be the same in all the servers.
29+
:param write_only: If set ot ``True``, only initialize to emit events. The
30+
default of ``False`` initializes the class for emitting
31+
and receiving.
2832
"""
2933
name = 'redis'
3034

31-
def __init__(self, url='redis://localhost:6379/0', channel='socketio'):
35+
def __init__(self, url='redis://localhost:6379/0', channel='socketio',
36+
write_only=False):
3237
if redis is None:
3338
raise RuntimeError('Redis package is not installed '
3439
'(Run "pip install redis" in your '
3540
'virtualenv).')
3641
self.redis = redis.Redis.from_url(url)
3742
self.pubsub = self.redis.pubsub()
38-
super(RedisManager, self).__init__(channel=channel)
43+
super(RedisManager, self).__init__(channel=channel,
44+
write_only=write_only)
3945

4046
def _publish(self, data):
4147
return self.redis.publish(self.channel, pickle.dumps(data))

tests/test_pubsub_manager.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ def test_custom_init(self):
2929
self.assertEqual(pubsub.channel, 'foo')
3030
self.assertEqual(len(pubsub.host_id), 32)
3131

32+
def test_write_only_init(self):
33+
mock_server = mock.MagicMock()
34+
pm = pubsub_manager.PubSubManager(write_only=True)
35+
pm.initialize(mock_server)
36+
self.assertEqual(pm.channel, 'socketio')
37+
self.assertEqual(len(pm.host_id), 32)
38+
self.assertEqual(pm.server.start_background_task.call_count, 0)
39+
3240
def test_emit(self):
3341
self.pm.emit('foo', 'bar')
3442
self.pm._publish.assert_called_once_with(

0 commit comments

Comments
 (0)