Skip to content

Commit

Permalink
More docs, some API permutation
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgodwin committed Jul 13, 2015
1 parent aa921b1 commit 8492dcd
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 34 deletions.
2 changes: 2 additions & 0 deletions channels/backends/redis_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,7 @@ def group_channels(self, group):
-1,
)

# TODO: send_group efficient implementation using Lua

def __str__(self):
return "%s(host=%s, port=%s)" % (self.__class__.__name__, self.host, self.port)
18 changes: 0 additions & 18 deletions channels/channel.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import random
import string

from django.utils import six

from channels import channel_backends, DEFAULT_CHANNEL_BACKEND


Expand Down Expand Up @@ -53,22 +51,6 @@ def as_view(self):
from channels.adapters import view_producer
return view_producer(self.name)

@classmethod
def consumer(self, *channels, alias=DEFAULT_CHANNEL_BACKEND):
"""
Decorator that registers a function as a consumer.
"""
# Upconvert if you just pass in a string
if isinstance(channels, six.string_types):
channels = [channels]
# Get the channel
channel_backend = channel_backends[alias]
# Return a function that'll register whatever it wraps
def inner(func):
channel_backend.registry.add_consumer(func, channels)
return func
return inner


class Group(object):
"""
Expand Down
24 changes: 24 additions & 0 deletions channels/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import functools

from django.utils import six

from channels import channel_backends, DEFAULT_CHANNEL_BACKEND


def consumer(self, *channels, alias=DEFAULT_CHANNEL_BACKEND):
"""
Decorator that registers a function as a consumer.
"""
# Upconvert if you just pass in a string
if isinstance(channels, six.string_types):
channels = [channels]
# Get the channel
channel_backend = channel_backends[alias]
# Return a function that'll register whatever it wraps
def inner(func):
channel_backend.registry.add_consumer(func, channels)
return func
return inner


# TODO: Sessions, auth
1 change: 1 addition & 0 deletions channels/interfaces/websocket_twisted.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def backend_reader(self):
"""
while True:
channels = self.factory.send_channels()
# TODO: Send keepalives
# Quit if reactor is stopping
if not reactor.running:
return
Expand Down
31 changes: 28 additions & 3 deletions docs/backend-requirements.rst → docs/backends.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
Channel Backend Requirements
============================
Backends
========

Multiple choices of backend are available, to fill different tradeoffs of
complexity, throughput and scalability. You can also write your own backend if
you wish; the API is very simple and documented below.

In-memory
---------

Database
--------

Redis
-----

Writing Custom Backends
-----------------------

Backend Requirements
^^^^^^^^^^^^^^^^^^^^

While the channel backends are pluggable, there's a minimum standard they
must meet in terms of the way they perform.
Expand All @@ -23,12 +42,14 @@ In particular, a channel backend MUST:

* Preserve the ordering of messages inside a channel

* Never deliver a message more than once
* Never deliver a message more than once (design for at-most-once delivery)

* Never block on sending of a message (dropping the message/erroring is preferable to blocking)

* Be able to store messages of at least 5MB in size

* Allow for channel and group names of up to 200 printable ASCII characters

* Expire messages only after the expiry period provided is up (a backend may
keep them longer if it wishes, but should expire them at some reasonable
point to ensure users do not come to rely on permanent messages)
Expand All @@ -41,6 +62,10 @@ In addition, it SHOULD:
* Provide a ``send_group()`` method which sends a message to every channel
in a group.

* Make ``send_group()`` perform better than ``O(n)``, where ``n`` is the
number of members in the group; preferably send the messages to all
members in a single call to your backing datastore or protocol.

* Try and preserve a rough global ordering, so that one busy channel does not
drown out an old message in another channel if a worker is listening on both.

0 comments on commit 8492dcd

Please sign in to comment.