I have added django.channels to a django project in order to support long running processes that notify users of progress via websockets.
Everything appears to work fine except for the fact that the implementation of the long running process doesn't seem to respond asynchronously.
For testing I have created an AsyncConsumer
that recognizes two types of messages 'run' and 'isBusy'.
The 'run' message handler sets a 'busy flag' sends back a 'process is running' message, waits asynchronously for 20 seconds resets the 'busy flag' and then sends back a 'process complete message'
The 'isBusy' message returns a message with the status of the busy flag.
My expectation is that if I send a run message I will receive immediately a 'process is running' message back and after 20 seconds I will receive a 'process complete' message. This works as expected.
I also expect that if I send a 'isBusy' message I will receive immediately a response with the state of the flag.
The observed behaviour is as follows:
- a message 'run' is sent (from the client)
- a message 'running please wait' is immediately received
- a message 'isBusy' is sent (from the client)
- the message reaches the web socket listener on the server side
- nothing happens until the run handler finishes
- a 'finished running' message is received on the client
- followed immediately by a 'process isBusy:False' message
Here is the implementation of the Channel listener:
class BackgroundConsoleConsumer(AsyncConsumer):
def __init__(self, scope):
super().__init__(scope)
self.busy = False
async def run(self, message):
print("run got message", message)
self.busy = True
await self.channel_layer.group_send('consoleChannel',{
"type":"consoleResponse",
"text":"running please wait"
})
await asyncio.sleep(20)
self.busy = False
await self.channel_layer.group_send('consoleChannel',{
"type":"consoleResponse",
"text": "finished running"
})
async def isBusy(self,message):
print('isBusy got message', message)
await self.channel_layer.group_send('consoleChannel',{
"type":"consoleResponse",
"text": "process isBusy:{0}".format(self.busy)
})
The channel is set up in the routing file as follows:
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter([
url("^console/$", ConsoleConsumer),
])
),
"channel": ChannelNameRouter({
"background-console":BackgroundConsoleConsumer,
}),
})
I run the channel with one worker (via ./manage.py runworker ).
The experiment was done with the django test server (via runserver).
Any ideas as to why the channel consumer does not appear to work asynchronously would be appreciated.