Спасибо большое, Узнал много нового, долго игрался с тасками, не обновлялся прайс, но почему-то когда создал новую подписку в ней все работало. Удалил старые и в новых все хорошо работает, очень интерсесно.
Можно в методе save() указать параметр update_fields в ф-ции set_price равный ('price', ) , в ф-ции set_comment равный ('comment', ). Тогда update в sql запросе не будет перезатирать все значения (можно чекнуть логи) объекта, а только указанные в update_fields. В данном случае эти 2 таски можно запустить параллельно.
Я просто взял этот кейс чтобы продемонстрировать проблему. В любом случае синглтон нужен , мы не можем всегда и везде это предусмотреть, особенно в немаленьких проектах
Спасибо за видосы, одна маленькая просьбочка! Перед выгрузкой видео ускоряй его слегка, потому что лично мне ютубовского 2х мало для просмотра твоего контента))
Можно зайти в контейнер и там уже писать команды,так image не будут создаваться ,а результат будет тот же, хотел тебе ещё задать вопрос - а почему не пользуешься тайпхинтами?
Да, согласен, через docker exec вроде так же работает. Тайпхинты - мы много спорили с коллегами по этому вопросу. Мое мнения что питон хорош тем, что это минималистичный, легко-читаемый язык. Если его превращать в Java по синтаксису, он никак не получит сильные стороны от Java, скорее получит его недостатки. в 99% случаев тайпхинты не нужны, когда и так очевидно что это за тип по названию. Но это зависит от проекта, конечно. Где-то они будут в тему. А вообще это спорный вопрос, кто-то прям за них всегда топит.
По поводу вашего вопроса. Как сделать так чтобы none не создавалось. Я в docker-compose после build вниз добавил image питона такой же как в Dockerfile. Вроде после этого перестает создаваться
Доброго времени суток! Благодарю за прекрасные курсы! Возник вопрос - если в Celery длительность очереди может быть большая, к примеру, час, то с этим возникают некоторые проблемы: - Если сервер перезагрузится по какой либо причине, таски исчезнуть, а значит и вся информация, которая должна была обновится, не будет обновляться. - Если я выключу сервер для обновления версии софта, то будет та же проблема - все таски слетят. Я чего-то не так понял и этих проблем не существует или для них уже есть решения?
Да, я думаю что проблемы будут скорее с тасками, которые уже запущены и в процессе выполнения на момент перезагрузки . Вроде была какая-то опция чтобы celery их перезапускал после перезагрузки, надо посмотреть в доке
а чем больше воркеров тем выше нагрузка на систему правильно? а если сам проект тяжелый? это же сильно по ресурсам бьет, есть ли альтернативные варианты выполнения тасков на такой случай?
Ну чем больше воркеров, тем больше запросов в базу, тем больше нагрузка на базу. Никак по-другому они систему не нагружают. Чтобы решить проблему нагрузки на базу лучше саму базу оптимизировать, добавить кеш, сделать еще read only базы и тд. Уменьшая количество Волкеров мы просто уменьшим производительность системы вцелом
А зачем мы используем transaction.atomic? Ведь select_for_update уже блокирует объекты модели для использования другим воркером. Если сделать то же самое без transaction.atomic, что изменится?
попробуй запускать команды в нужном контейнере через следующую команду: "docker-compose exec containe_name some_command_in_container" и в этом случае не будет создаваться новый контейнер
Еще раз спасибо! Офигенный разбор! 👍👍👍 Правда, у меня косяк не воспроизводится, 😄 видимо, потому что я пошел путем апдейтов, а не сейвов: def set_price_from_service(service_instance_id): from .models import Subscription, Service time.sleep(10) service_instance = Service.objects.get(id=service_instance_id) queryset = service_instance.subscriptions.select_related('plan').only('plan__discount_percent', 'service_id') subscriptions = [] for i_subscription in queryset: new_price = service_instance.price - service_instance.price * i_subscription.plan.discount_percent / 100 i_subscription.price = new_price subscriptions.append(i_subscription) Subscription.objects.bulk_update(subscriptions, fields=['price']) @shared_task() def set_comment(service_instance_id): from .models import Subscription, Service service_instance = Service.objects.get(id=service_instance_id) queryset = service_instance.subscriptions.all() subscriptions = [] for i_subscription in queryset: i_subscription.comment = str(datetime.datetime.now()) subscriptions.append(i_subscription) time.sleep(20) Subscription.objects.bulk_update(subscriptions, fields=['comment'])
Я не до конца понял необходимости добавления в запрос select_for_update? Зачем? Судя по доке, лочит строки в таблице, но мы вроде также используем менеджер transaction.atomic, который гарантирует, что операция будет выполнена полностью или не выполнена вовсе.... Можно пояснить подробнее про эту связку?
Это разные вещи. Atomic делает операцию атомарной, а select for update чтобы параллельные таски не пытались изменить объект , по тому что их изменения могут быть перезаписаны . На видео я опытным путем подтверждаю эту необходимость , если досмотреть до конца .
Почему когда вы добавили транзакции и воркеры разобрали таски, один таск закончился намного раньше и не ждал 20+27 секунд? Куда делись эти самые sleep?
Привет. Ну в видео я показал два варианта: без трансакции и с ней. И то, как трансакция решает показанную проблему. Уровни изоляции они присутствуют в трансакциях. Без них не существуют. Тут же проблема что мы создали объект кода python , и он устарел , пока мы что-то делали , а потом мы его сохранили и он перезатер. Вообщем это немного другая ситуация.