django / django/channels

Channel Layer doesn't work for AsyncHttpConsumer

Open
#1,302 6 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
6.4k
Forks
826
PR merge metrics
No merged PRs in 30d

Description

  • Your OS and runtime environment, and browser if applicable
    MacOS 10.13.6 x64, Python 3.5.3, Django version 2.0.5, ASGI/Channels version 2.1.6
  • A pip freeze output showing your package versions
absl-py==0.2.2
astor==0.6.2
astroid==1.6.4
bleach==1.5.0
CacheControl==0.12.4
cachetools==2.1.0
certifi==2018.4.16
channels==2.1.6
chardet==3.0.4
click==6.7
decorator==4.3.0
dj-database-url==0.5.0
Django==2.0.5
djangorestframework==3.8.2
firebase-admin==2.10.0
future==0.16.0
gast==0.2.0
gcloud==0.17.0
geocoder==1.38.1
google-api-core==1.2.0
google-auth==1.4.1
google-cloud-core==0.28.1
google-cloud-firestore==0.29.0
google-cloud-storage==1.10.0
google-resumable-media==0.3.1
googleapis-common-protos==1.5.3
googlemaps==2.5.1
grpcio==1.12.0
gunicorn==19.8.1
html5lib==0.9999999
httplib2==0.11.3
idna==2.6
isort==4.3.4
jws==0.1.3
lazy-object-proxy==1.3.1
Markdown==2.6.11
mccabe==0.6.1
msgpack-python==0.5.6
numpy==1.14.3
oauth2client==3.0.0
protobuf==3.5.2.post1
pyasn1==0.4.3
pyasn1-modules==0.2.1
pycryptodome==3.4.3
pylint==1.9.1
python-jwt==2.0.1
pytz==2018.4
ratelim==0.1.6
requests==2.11.1
requests-toolbelt==0.7.0
reverse-geocoder==1.5.1
rsa==3.4.2
scipy==1.1.0
six==1.11.0
tensorboard==1.8.0
tensorflow==1.8.0
termcolor==1.1.0
urllib3==1.22
Werkzeug==0.14.1
whitenoise==3.3.1
wrapt==1.10.11
Pyrebase==3.0.27
psycopg2
django-cors-headers
  • What you expected to happen vs. what actually happened
    This is my LongPollingConsumer where inside handle I am storing the channel_name in a database then doing the usual as documented here.
class LongPollConsumer(AsyncHttpConsumer):
  async def handle(self, body):
    self.room_name = self.scope['url_route']['kwargs']['uuid']
    # self.room_group_name = 'upvote_'
    # await self.send_response(200, b"Hello", headers=[
    #     (b"Content-Type", b"application/json"),
    # ])
    store_channel(self.room_name, self.channel_name)
    await self.send_headers(status=200, headers=[
        (b"Content-Type", b"application/json"),
    ])
    print('consumer room_name', self.room_group_name)
    # await self.channel_layer.group_add(
    #     self.room_group_name,
    #     self.channel_name
    # )

    # Headers are only sent after the first body event.
    # Set "more_body" to tell the interface server to not
    # finish the response yet:
    await self.send_body(body=b"Response", more_body=True)

  async def upvote_message(self, event):
    delete_channel(self.room_name)
    print(event['message'])
    # Send JSON and finish the response:
    # async_to_sync(self.channel_layer.group_discard)(
    #     self.room_group_name,
    #     self.channel_name
    # )
    await self.send_body(body=json.dumps(event).encode("utf-8"))

handle is invoked as it should be. Then from my views.py, I am retrieving list of channels from the database and dispatching the handler(upvote_message) with an event message

channel_layer = get_channel_layer()
channels = retrieve_channels(uuid)
for channel in channels.keys():
    print('dispatching to channel', channel)
    async_to_sync(channel_layer.send)(
    channel, {
            "type": "upvote.message",
            "message": {
                'actionType': 'UPVOTES_LONG_POLL_RESPONSE',
                'data': {}
            }
        }
    )

Expected behaviour is that for every channel_layer.send, the async method upvote_message inside my LongPollingConsumer should be invoked with appropriate event message and close the respective HTTP connection. But nothing is happening. From views.py, it prints

sending to channel specific..inmemory!KTTXyBUZnIwj
sending to channel specific..inmemory!bafQMBaSCOmu
sending to channel specific..inmemory!zAGgrVeMWNth
sending to channel specific..inmemory!tazNTCBhKvfh
sending to channel specific..inmemory!XuMVhdIjBCAi

and the curl (using curl -X GET http://localhost:8000/lp/upvote/-L_v3R0Xp-BlOeagBuu1/ --verbose) remains stuck at:

*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /lp/upvote/-L_v3R0Xp-BlOeagBuu1/ HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Transfer-Encoding: chunked
<

then eventually after manually closing connection,

* transfer closed with outstanding read data remaining
* stopped the pause stream!
* Closing connection 0
  • How you're running Channels (runserver? daphne/runworker? Nginx/Apache in front?)
    python manage.py runserver development server
  • Console logs and full tracebacks of any errors
    Absolutely no logs generated except and the print statements in the code above.
Django version 2.0.5, using settings 'AppName.settings'
Starting ASGI/Channels version 2.1.6 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the LongPollConsumer in the issue and the dispatch loop in views.py, then reproduce it with python manage.py runserver and the provided curl command. Trace whether the channel_layer.send calls reach upvote_message; done means each dispatched event invokes that handler and completes the corresponding long-polling response.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.