summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2014-04-01 14:32:24 -0700
committerAndy McCurdy <andy@andymccurdy.com>2014-04-01 14:32:24 -0700
commit9e5b10c6d0753bb536dff362aa23f27b156d3562 (patch)
tree3f6104bb90fecfe3d3fc596d520af9c8cbaa04d0
parent54e5b062e2eddd674c9a462f763a7854965832d2 (diff)
downloadredis-py-9e5b10c6d0753bb536dff362aa23f27b156d3562.tar.gz
pubsub docs
-rw-r--r--README.rst191
1 files changed, 191 insertions, 0 deletions
diff --git a/README.rst b/README.rst
index 8eed776..5ad583e 100644
--- a/README.rst
+++ b/README.rst
@@ -319,6 +319,197 @@ which is much easier to read:
>>> r.transaction(client_side_incr, 'OUR-SEQUENCE-KEY')
[True]
+Publish / Subscribe
+^^^^^^^^^^^^^^^^^^^
+
+redis-py includes a `PubSub` object that subscribes to channels and listens
+for new messages. Creating a `PubSub` object is easy:
+
+.. code-block:: pycon
+
+ >>> r = redis.StrictRedis(...)
+ >>> p = r.pubsub()
+
+Once a `PubSub` instance is created, channels and patterns can be subscribed
+to:
+
+.. code-block:: pycon
+
+ >>> p.subscribe('my-first-channel', 'my-second-channel', ...)
+ >>> p.psubscribe('my-*', ...)
+
+The `PubSub` instance is now subscribed to those channels/patterns. The
+subscription confirmations can be seen by reading messages off the `PubSub`
+instance:
+
+.. code-block:: pycon
+
+ >>> p.get_message()
+ {'pattern': None, 'type': 'subscribe', 'channel': 'my-second-channel', 'data': 1L}
+ >>> p.get_message()
+ {'pattern': None, 'type': 'subscribe', 'channel': 'my-first-channel', 'data': 2L}
+ >>> p.get_message()
+ {'pattern': None, 'type': 'psubscribe', 'channel': 'my-*', 'data': 3L}
+
+Every message read from a `PubSub` instance will be a dictionary with the
+following keys:
+
+* **type**: One of the following: 'subscribe', 'unsubscribe', 'psubscribe',
+ 'punsubscribe', 'message', 'pmessage'
+* **channel**: The channel [un]subscribed to or the channel a message was
+ published to
+* **pattern**: The pattern that matched a published messages channel. Will be
+ None in all cases except for 'pmessage' types.
+* **data**: The message data. With [un]subscribe messages, this value will be
+ the number of channels and patterns the connection is currently subscribed
+ to. With [p]message messages, this value will be the actual published
+ message.
+
+Let's send a message now.
+
+.. code-block:: pycon
+
+ # the publish method returns the number matching channel and pattern
+ # subscriptions. 'my-first-channel' matches both the 'my-first-channel'
+ # subscription and the 'my-*' pattern subscription, so this message will
+ # be delivered to 2 channels/patterns
+ >>> r.publish('my-first-channel', 'some data')
+ 2
+ >>> p.get_message()
+ {'channel': 'my-first-channel', 'data': 'some data', 'pattern': None, 'type': 'message'}
+ >>> p.get_message()
+ {'channel': 'my-first-channel', 'data': 'some data', 'pattern': 'my-*', 'type': 'pmessage'}
+
+Unsubscribing works just like subscribing. If no arguments are passed to
+[p]unsubscribe, all channels or patterns will be unsubscribed from:
+
+.. code-block:: pycon
+
+ >>> p.unsubscribe()
+ >>> p.punsubscribe('my-*')
+ >>> p.get_message()
+ {'channel': 'my-second-channel', 'data': 2L, 'pattern': None, 'type': 'unsubscribe'}
+ >>> p.get_message()
+ {'channel': 'my-first-channel', 'data': 1L, 'pattern': None, 'type': 'unsubscribe'}
+ >>> p.get_message()
+ {'channel': 'my-*', 'data': 0L, 'pattern': None, 'type': 'punsubscribe'}
+
+redis-py also allows you to register callback functions to handle published
+messages. Message handlers take a single argument, the message, which is a
+dictionary just like the examples above. To subscribe to a channel or pattern
+with a message handler, pass the channel or pattern name as a keyword argument
+with a value of the callback function.
+
+When a message is read on a channels or pattern with a message handler, the
+message dictionary is created and passed to the message handler. A None value
+is returned from get_message().
+
+.. code-block:: pycon
+
+ >>> def my_handler(message):
+ ... print 'MY HANDLER: ', message['data']
+ >>> p.subscribe(**{'my-channel': my_handler})
+ >>> p.get_message()
+ {'pattern': None, 'type': 'subscribe', 'channel': 'my-channel', 'data': 1L}
+ >>> r.publish('my-channel', 'awesome data')
+ 1
+ # for the message handler to work, we need tell the instance to read data.
+ # this can be done in several ways (read more below). we'll just use
+ # the familiar get_message() function for now
+ >>> message = p.get_message()
+ MY HANDLER: awesome data
+ # note here that the my_handler callback printed the string above.
+ # `message` is None because the message was handled by our handler.
+ >>> print message
+ None
+
+If your application is not interested in the (sometimes noisy)
+subscribe/unsubscribe messages, you can pass `ignore_subscribe_messages=True`
+to redis.pubsub(). This will cause all subscribe/unsubscribe messages to be
+read, but they won't bubble up to your application:
+
+.. code-block:: pycon
+
+ >>> p = r.pubsub(ignore_subscribe_messages=True)
+ >>> p.subscribe('my-channel')
+ >>> p.get_message() # hides the subscribe message and returns None
+ >>> r.publish('my-channel')
+ 1
+ >>> p.get_message()
+ {'channel': 'my-channel', data': 'my data', 'pattern': None, 'type': 'message'}
+
+There are three different strategies for reading messages.
+
+The examples above have been using `pubsub.get_message()`. Behind the scenes,
+`get_message()` uses the system's 'select' module to quickly poll the
+connection's socket. If there's data available to be read, `get_message()` will
+read it, format the message and return it or pass it to a message handler. If
+there's no data to be read, `get_message()` will immediately return None. This
+makes it trivial to integrate into an event loop inside your application:
+
+.. code-block:: pycon
+
+ >>> while True:
+ >>> message = p.get_message()
+ >>> if message:
+ >>> # do something with the message
+ >>> time.sleep(0.001) # be nice to the system :)
+
+Older versions of redis-py only read messages with `pubsub.listen()`. listen()
+is a generator that blocks until a message is available. If your application
+doesn't need to do anything else but receive and act on messages received from
+redis, listen() is an easy way to get up an running:
+
+.. code-block:: pycon
+
+ >>> for message in p.listen():
+ ... # do something with the message
+
+The third option runs an event loop in a separate thread.
+`pubsub.run_in_thread()` creates a new thread and starts the event loop. The
+thread object is returned the caller of `run_in_thread()`. The caller can
+use the `thread.stop()` method to shut down the event loop and thread. Behind
+the scenes, this is simply a wrapper around `get_message()` that runs in a
+separate thread, essentially creating a tiny non-blocking event loop for you.
+`run_in_thread()` takes an optional `sleep_time` argument. If specified, the
+event loop will call `time.sleep()` with the value in each iteration of the
+loop.
+
+Note: Since we're running in a separate thread, there's no way to handle
+messages that aren't automatically handled with registered message handlers.
+Therefore, redis-py prevents you from calling `run_in_thread()` if you're
+subscribed to patterns or channels that don't have message handlers attached.
+
+.. code-block:: pycon
+
+ >>> p.subscribe(**{'my-channel': my_handler})
+ >>> thread = p.run_in_thread(sleep_time=0.001)
+ # the event loop is now running in the background processing messages
+ # when it's time to shut it down...
+ >>> thread.stop()
+
+A PubSub object adheres to the same encoding semantics as the client instance
+it was created from. Any channel or pattern that's unicode will be encoded
+using the `charset` specified on the client before being sent to Redis. If the
+client's `decode_responses` flag is set the False (the default), the
+'channel', 'pattern' and 'data' values in message dictionaries will be byte
+strings (str on Python 2, bytes on Python 3). If the client's
+`decode_responses` is True, then the 'channel', 'pattern' and 'data' values
+will be automatically decoded to unicode strings using the client's `charset`.
+
+PubSub objects remember what channels and patterns they are subscribed to. In
+the event of a disconnection such as a network error or timeout, the
+PubSub object will re-subscribe to all prior channels and patterns when
+reconnecting. Messages that were published while the client was disconnected
+cannot be delivered. When you're finished with a PubSub object, call its
+`.close()` method to shutdown the connection.
+
+.. code-block:: pycon
+
+ >>> p = r.pubsub()
+ >>> ...
+ >>> p.close()
+
LUA Scripting
^^^^^^^^^^^^^