Channels: How to use timer in django channel on connect?

Created on 16 Nov 2017  路  7Comments  路  Source: django/channels

I want to send data from the worker to every client that connected to the particular group. The changes never occur in client side. Every 100 ms server publish data and and subscriber (in javascript connect to django) changes and showing data. It's easy using node with setInterval, but how to implement in django? Thanks

Most helpful comment

I think I solved it, although I am not sure if it is the best way (please let me know if it is)
I changed the await by asyncio.create_task(), like this:

async def connect(self):
    asyncio.create_task(self.start_periodic_task())

All 7 comments

You have to manually manage something like this with channels 1 using, for example, a management command.

What is best practice for Django Channels v2?

If you wanted to do something every 100ms in Channels 2, you would use an AsyncConsumer that launched a coroutine when it started up that did something like:

while True:
    await asyncio.sleep(0.1)
    await self.send(...)

Make sure that you store the coroutine on self, though, and kill it when you get a disconnect or you'll leave it running when the socket closes. For more substantial handling, you may want to override the __call__ method and wrap it in a try/finally with a cancel.

Hi Andrew, thanks for the suggestion, how should I start that coroutine?

Right now I am doing something like this on my consumer (AsyncWebsocketConsumer):

async def start_periodic_task(self):
    while True:
            await send(...
            await asyncio.sleep(0.5)

async def connect(self):
    await self.start_periodic_task()

But the execution is stopped after a while with this message:

Application instance <Task pending coro=<AsyncConsumer.__call__() running at .../venv/lib/python3.7/site-packages/channels/consumer.py:62> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f4630029918>()]>> for connection <WebSocketProtocol client=['127.0.0.1', 32914] path=b'/stream/'> took too long to shut down and was killed

I think the problem is that I am awaiting the coroutine, how can I just launch it and not await it in the connect() method?

I think I solved it, although I am not sure if it is the best way (please let me know if it is)
I changed the await by asyncio.create_task(), like this:

async def connect(self):
    asyncio.create_task(self.start_periodic_task())

@sfehlandt I also want to implement a similar logic, but I cannot kill it, such as: took too long to shut down and was killed. sir, how did you do it

@qq854051086 I did it like I posted before but used asyncio.ensure_future() instead of asyncio.create_task(). The function returns a reference to the future object, so you can store that in a variable and then cancel it. Like this:

class MyConsumer(AsyncJsonWebsocketConsumer):

    async def run_periodic_task(self):
        while True:
                await send(...
                await asyncio.sleep(0.5)

    async def connect(self):
        self.my_task = await asyncio.ensure_future(self.run_periodic_task())

Then if you want to cancel it:

self.my_task.cancel()

Hope it helps
Cheers

Was this page helpful?
0 / 5 - 0 ratings