Django - долго выполняемые задачи
Я ищу и совет по поводу долго выполняющихся задач в Django. Вот мой пример использования: У меня есть заказ в eshop с более чем 200 товарами (строками). Когда я нажимаю на "обработать", Django запускает функцию (которая состоит из нескольких более мелких функций) для обработки данных. Это может занять некоторое время, но пока эта задача выполняется, я хочу сообщить пользователю о состоянии процесса. В это время заказ "заблокирован". Моя текущая теория заключается в использовании комбинации Django Celery (или его эквивалента) и Django channels. Как только задача будет выполнена, каналы передадут сообщение через websocket на фронтенд, а JS изменит объекты (кнопку, статус, тексты...). Когда задача начинается, функция обновляет статус в DB. После завершения задачи статус в DB обновляется снова. Поскольку приложение не SPA и я использую стандартные представления и шаблоны Django, это решение не будет работать в случае, если задача завершится во время обновления страницы. Таким образом, после того, как страница загрузится снова, задача не будет запущена, WS не будет посылать никаких обновлений, но в то же время запрос в DB будет иметь старый статус. Пример: Когда процесс запускается, я сохраняю статус как "запущен". Когда задача Celery завершена, статус в DB меняется на "done". Во время перезагрузки страницы (после нажатия кнопки "процесс") задача завершилась, БД обновилась, НО запрос к БД получил старое значение статуса. В результате после перезагрузки страницы Vie и шаблон имеют статус "выполняется", но в БД уже "сделано" - не вовремя. Как решить эту проблему? Как выйти из этой ситуации? Я не хочу вручную задерживать выполнение задачи.
В случае, если время выполнения функции меньше 30 секунд - я бы предложил не заморачиваться с Celery и просто поместить все в request.
В случае, если вы действительно должны использовать Celery, вы можете реализовать это следующим образом:
- Создайте некоторую модель Django для отслеживания задач. В ней будет некоторое поле ID (значение которого вы будете возвращать сразу после завершения запроса, и оно будет использоваться некоторым JS-кодом). Также вы можете поместить туда все входные данные для задачи Celery, и там будет
status
поле. - В JS-коде, если вам это не фактически нужно, я бы не заморачивался с WebSockets - старого доброго поллинга должно быть достаточно для реализации периодических проверок состояния вашей задачи.
- JS-код должен послать запрос к некоторой конечной точке, которая вернет значение поля
state
для задачи.
В дополнение к полю state
вы также можете вернуть некоторые сведения о фактическом прогрессе (если это позволяет логика).