Channel Layer doesn't work for AsyncHttpConsumer
See original GitHub issue- 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 freezeoutput 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
handleI am storing thechannel_namein 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 runserverdevelopment 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.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:6
Top Results From Across the Web
Consumers — Channels 4.0.0 documentation
If no channel layer is configured or the channel layer doesn't support groups, connecting to a WebsocketConsumer with a non-empty groups attribute will...
Read more >Interactions between HTTP and websocket connections in ...
I was able to get this to work using either two group names or two channel names. Also knowing http_reponse would end the...
Read more >Channels Documentation - Read the Docs
ChatConsumer only uses async-native libraries (Channels and the channel layer) and in particular it does not access synchronous Django models.
Read more >django-channels - Bountysource
Channel Layer doesn't work for AsyncHttpConsumer $ 0. Created 3 years ago in django/channels with 3 comments. Your OS and runtime environment, and...
Read more >Channels - Developer-friendly asynchrony for Django
Note that the path doesn't matter for routing; any WebSocket ... 它们与 worker server 解耦,而由 channel layer 传输 channel 的内容。
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

So, I did a little more digging into the channels source code, and my investigation led me to this and this.
The
await_many_dispatchmethod is the one responsible for dispatching stuff likehttp.request,websocket.connect, and all other custom “events” sent. ForAsyncHttpConsumer, thehttp.requestevent will be dispatched to thehttp_requestmethod.According to the source code, the
http_requestmethod will always raise aStopConsumerexception once thehandlemethod has finished. This exception will, in turn, trigger thefinallyclause inawait_many_dispatchwhich will cancel all tasks, including the task handling channel layer events.Putting in a
whileloop inside thehandlemethod will also not work, because it is called from inside the task handlinghttp.request, and if that task does not end, the task handling channel layer events will not be given a chance to run.What I did to validate my findings was to use a
keepaliveflag that will be turned on ifsend_bodywas invoked withmore_body=True, and if that flag is on, theStopConsumerexception will not be raised. With the example code below, I can get thechat_messagemethod to trigger.I am not sure what other stuff this might break, but I can submit a PR if this is adequate, otherwise I will defer to the masters. At the very least, part of the investigation has already been performed, and hopefully this helped save some time.