I have a Django 5 application that use websockets using channels, and I'm trying to switch to AsyncConsumers to take advantage of asyncronous execution for I/O or external API tasks.
I already wrote a demo project and everything it's working fine, however in my application I use Django signals, and I have a long I/O task to be performed in the post_save of MyModel, previously implemented using threads:
from asyncio import sleep
@receiver(dj_models.signals.post_save, sender=MyModel)
async def auto_process_on_change(sender, instance, **kwargs):
logger.log("Starting Long Save task");
await sleep(30)
logger.log("Starting Long Save task");
The websocket consumer that is serving the request is similar to the following:
from channels.generic import websocket
class AsyncGenericConsumer(websocket.AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
...
async def receive_json(self, message):
...
user = await User.objects.aget(id=...)
# Authentication code
# ....
# (eventually) Create MyModel, depending on request type
mod = await my_models.MyModel.objects.acreate(...)
Now, the problem is as follow:
When Alice's request is still performing a post_save operation (i.e., awaiting the long task contained in it) and a Bob user opens up the browser and makes a request to the same consumer, the computation gets stuck to user = await User.objects.aget(id=...) until the long task (e.g., the asyncio.sleep(30)) terminates for Alice.
The actual application is much more complex than this and we can't get rid of the post_save.
I would like to understand how the .aget() on a model could get locked by a post_save on another model, when they should be asynchronous calls and be processed as such.
Are there ways to avoid this while still using asyncio code?
I am using the latest versions of all the packages involved.
Thanks for your support.
await asyncio.sleep(). The database is postgres.