Почему асинхронный пост-сохранение Django Signals блокирует другие асинхронные вызовы ORM?
У меня есть приложение Django 5, использующее веб-сокеты с помощью channels
, и я пытаюсь перейти на AsyncConsumers, чтобы использовать преимущества асинхронного выполнения для ввода-вывода или внешних задач API.
Я уже написал демо-проект и все работает нормально, однако в моем приложении я использую Django signals
, и у меня есть длинная задача ввода-вывода, которая должна быть выполнена в post_save
из MyModel
, ранее реализованная с помощью потоков:
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");
Потребитель websocket, обслуживающий запрос, выглядит следующим образом:
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(...)
Теперь проблема заключается в следующем:
Когда запрос Alice все еще выполняет операцию post_save
(т.е, ожидая выполнения содержащейся в нем длинной задачи), а пользователь Bob открывает браузер и делает запрос к тому же потребителю, вычисление застревает на user = await User.objects.aget(id=...)
до тех пор, пока длинная задача (например, asyncio.sleep(30)
) не завершится для Алисы.
Реальное приложение намного сложнее, чем это, и мы не можем избавиться от post_save
.
Я хотел бы понять, как .aget()
на модели может быть заблокирован post_save
на другой модели, когда они должны быть асинхронными вызовами и обрабатываться как таковые.
Есть ли способы избежать этого, продолжая использовать код asyncio?
Я использую последние версии всех задействованных пакетов.
Спасибо за поддержку.