Django Loop Through Objects After Bulk .update()
Этот код запускается по cron. Поэтому я хочу обновить статус объектов немедленно, чтобы эти объекты не были подняты снова, если второй cron запустится до того, как закончится текущий (что в конечном итоге начнет происходить с моим приложением.)
# Grab all pending emails.
emails = delivery_que.objects.filter(status='PENDING')
emails.update(status='SENDING')
# Loop through the pending emails.
for email in emails:
Текущий код не работает, так как у меня, похоже, больше нет доступа к объектам после того, как я .update() их.
Вот обходной путь, который я применил:
# Grab all pending emails.
emails = delivery_que.objects.filter(status='PENDING')
emails.update(status='SENDING')
emails = delivery_que.objects.filter(status='SENDING')
# Loop through the pending emails.
for email in emails:
Есть ли другое лучшее решение, которое я упускаю? Я бы предпочел не запрашивать базу данных снова, чтобы повторно выбрать объекты, к которым у меня уже должен быть доступ из первого запроса.
Проблема здесь в том, что вы запускаете перекрывающиеся процессы, и ни один из них не знает, что делает другой в любой момент времени.
Простое решение:
- При запуске задания проверьте наличие записи о блокировке. Если таковая существует, завершите работу.
- Добавить запись о блокировке (к модели в БД, коснуться файла, что-то еще).
- Обработайте задание.
- Снять запись блокировки как последнее, что делает задание.
Слегка более сложное решение:
- В начале работы обновите все записи из
PENDING
до уникального значения для данного процесса (например,PROCESSING_<uuid>
) .
- Запустите обновление для записей с этим уникальным значением.
Вы также можете сделать это, добавив в модель еще одно поле, например processing_id
и проверив, что оно пустое, а также имеет правильный PENDING
статус.
Возможно, самое сложное решение:
- Сделать процесс идемпотентным ...
Под этим я подразумеваю, что не имеет значения, если он выполняется дважды на одной и той же записи. Судя по приведенному вами коду, это действительно так, поскольку все, что вы делаете, это меняете статус на SENDING
, но я предполагаю, что есть код, который вы не показываете, и пользователи получают двойные письма.
Если у вас есть код, гарантирующий, что не будет отправлено двойное письмо, это не будет проблемой - объект может быть обработан дважды, но письмо будет отправлено только в первый раз.
В идеальном мире все процессы, подобные этому, в любом случае должны быть идемпотентными, просто чтобы гарантировать, что у вас никогда не будет никаких проблем, если кому-то удастся запустить его, когда он не должен этого делать.
Такая же проблема здесь: how-to-bulk-update-with-django и Документация Django здесь Bulk Update