Дорогостоящие вычисления в django должны выполняться при изменении модели
Я работаю над django-приложением, в котором есть модель с полем, которое должно вычисляться при изменении модели. Само вычисление относительно дорого (1+ секунды), особенно если/когда это поле пересчитывается для большого набора запросов. Важно, чтобы это поле пересчитывалось сразу после изменения модели, поскольку оно определяет рабочий процесс, которому должен следовать пользователь, и значение поля передается в пользовательский интерфейс, чтобы пользователь мог его увидеть. Как минимум, расчет должен гарантированно выполняться после обновления или каким-то образом указывать на то, что расчет устарел.
Текущая реализация, которая не была проблемой, поскольку ранее расчет был менее сложным/дорогим (до внесения изменений клиентом), выглядит следующим образом:
- пользователь вносит изменения в пользовательский интерфейс, и модель обновляется
- API получает изменения и применяет их к модели
- модель .save() переопределяется, поэтому поле вычисляется и устанавливается
При такой реализации мы также отключили менеджер queryset в модели, чтобы предотвратить использование .update() для обеспечения того, чтобы поле всегда пересчитывалось при .save().
Мне интересно, как другие реализовали бы нечто подобное, чтобы быть как можно более эффективными и не полагаться на блокировку сохранения для завершения.
На этот вопрос нет универсального ответа.
Вариант A: Функция/вычисление потенциально может завершиться неудачей.
В этом случае вы хотите уведомить пользователя об успешном сохранении экземпляра модели или нет. В этом случае пользователь должен подождать, пока вычисления завершатся успешно, или увидеть страницу ошибки.
Вариант B: Функция/вычисление может (почти) не завершиться неудачей.
Как и в случае со всеми дорогостоящими функциями, вы можете «передать» сохранение модели, включая дорогостоящие вычисления, другому сервису (скорее всего, celery).
Когда вы разворачиваете проект django, обслуживанием ответа занимается один рабочий пул (например, uwsgi). Аутсорсинговая функциональность выполняется другим рабочим пулом (реализованным через celery). Это позволяет обрабатывать функции и задачи асинхронно, в то время как ответ быстро отправляется пользователю.
Единственный недостаток такого подхода заключается в том, что успешность работы аутсорсинговой функциональности сложно передать пользователю и за этим нужно следить.