Должны ли экземпляры объекта модели django передавать сельдерею?

# models.py
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    text_blob = models.CharField(max_length=50000)

# tasks.py
import celery
@celery.task
def my_task(person):
    # example operation: does something to person 
    # needs only a few of the attributes of person
    # and not the entire bulky record
    person.first_name = person.first_name.title()
    person.last_name = person.last_name.title()
    person.save()

В моем приложении где-то есть что-то вроде:

from models import Person
from tasks import my_task
import celery
g = celery.group([my_task.s(p) for p in Person.objects.all()])
g.apply_async()
  • Сорняки сельдерея p, чтобы отправить его правителю?
  • Если рабочие работают на нескольких машинах, будет ли передан весь объект (вместе с громоздким text_blob, который в первую очередь не требуется) по сети? Есть ли способ избежать этого?
  • Как я могу эффективно и равномерно распределять записи Person сотрудникам, работающим на нескольких машинах?

  • Может ли это быть лучшей идеей? Разве это не ошеломило бы db, если бы у человека было несколько миллионов записей?

    # tasks.py
    
    import celery
    from models import Person
    @celery.task
    def my_task(person_pk):
        # example operation that does not need text_blob
        person = Person.objects.get(pk=person_pk)
        person.first_name = person.first_name.title()
        person.last_name = person.last_name.title()
        person.save()
    
    
    #In my application somewhere
    from models import Person
    from tasks import my_task
    import celery
    g = celery.group([my_task.s(p.pk) for p in Person.objects.all()])
    g.apply_async()
    

Ответ 1

Я считаю, что лучше и безопаснее передавать ПК, а не весь объект модели. Поскольку PK - всего лишь число, сериализация также намного проще. Самое главное, вы можете использовать более безопасный sarializer (json/yaml вместо рассола) и иметь спокойствие, что у вас не будет проблем с сериализацией вашей модели.

Как эта статья гласит:

Поскольку сельдерей - это распределенная система, вы не можете знать, в каком процессе или даже на какой машине будет выполняться задача. Таким образом, вы не должны передавать объекты модели Django в качестве аргументов для задач, поэтому почти всегда лучше повторно извлекать объект из базы данных, поскольку существуют возможные условия гонки.

Ответ 2

Да. Если в базе данных есть миллионы записей, то это, вероятно, не самый лучший подход, но поскольку вам нужно пройти через все миллионы записей, то в значительной степени независимо от того, что вы делаете, ваша БД будет сильно ударяться трудно.

Вот несколько альтернатив, ни один из которых я бы назвал "лучше", просто разные.

  • Реализуйте обработчик сигнала pre_save для вашего класса Person, который использует материал .title(). Таким образом, ваши first_name/last_names будут всегда правильно храниться в db, и вам больше не придется это делать.
  • Используйте команду управления, которая принимает какой-то параметр поискового вызова... возможно, используйте первую букву последнего имени для сегментации Лица. Таким образом, запуск ./manage.py my_task a будет обновлять все записи, где фамилия начинается с "a". Очевидно, вам придется запускать это несколько раз, чтобы пройти через всю базу данных.
  • Возможно, вы можете сделать это с помощью какого-нибудь творческого sql. Я даже не собираюсь здесь пытаться, но, возможно, стоит изучить.

Имейте в виду, что .save() будет более тяжелым "ударом" в базу данных, а затем фактически выберите миллионы записей.