Комментарии 13
Сейчас будет критика. К переводчику замечаний почти нет кроме вопроса - зачем вы выбрали это невнятное бормотание двухлетней давности для перевода?
Во-первых, все примеры и "объяснения" в этой статье - только для Redis-брокера. Если использовать RabbitMQ - там нет никаких "unacked" очередей и работа сделана через родные AMQP-механизмы. Более того, сама celery ничего не знает про этих брокеров и использует еще несколько библиотек (того же автора) более низкого уровня для транспорта (kombu, amqplib), для работы с процессами (billiard), для сериализации и тп.
Брокеров тоже может быть довольно много разных и механизм работы с каждым движком тоже будет отличаться. Лучше всего использовать RabbitMQ, но проще всего Redis - поэтому он во всех примерах и идет.
Сама по себе Celery - тот еще здоровый комбайн. Неочевидных моментов там, действительно, на два вагона наберется. Я с ней работаю уже лет 10 и примерно знаю что делать не надо, однако фич в ней, конечно, дофига.
Не очень понятно какие "неочевидные моменты" проясняет эта статья. На мой взгляд, только запутывает. Можно было бы рассказать о более насущных вещах: как правильно делать scheduled-таски, как масштабировать и отменять задачи, как запускать в продакшене, как делать мониторинг. И совсем уж актуальное - как организовать выполнение долгих тасков, отправляя их из асинхронного фреймворка типа FastAPI или даже из другого языка.
Да, действительно, возможно, это не самая лучшая статья для перевода. Но, честно, я не нашел чего-то более вразумительного. Возможно, плохо искал) Если поделитесь в комментах -- я только за ?
Большинство статей рассказывают, как просто поднять Celery в Django. Ну максимум еще скажут, что есть какой-то там брокер сообщений и система воркеров с очередями.
А лично для меня, не имеющего 10 лет опыта, эта статья ответила на некоторые вопросы.
напишите сами такую статью, было бы интересно почитать
Действительно, я бы с удовольствием посмотрел на пример production-ready Celery сервиса, который крутится в docker контейнере.
В Celery всё очень плохо с asyncio
Почему статья в хабе Django?
Ну не так уж и плохо. Если не использовать eventlet/greenlet, то можно взять eventloop и запустить асинхронные таски. Главное - дождаться их завершения. У меня довольно неплохо работает такой механизм для скачивания пачки файлов.
Вот с чем плохо - так это с потоками, насколько я помню. Не знаю уже как в последних версиях, но в (старой) версии 3 категорически нельзя было запускать потоки внутри таски. Если не починили ничего, то и всякие sync_to_async тоже могут не работать нормально.
eventlet/greenlet
Предлагаете дублировать код?
можно взять eventloop и запустить асинхронные таски
одну. асинхронную. таску. Э -- эффективность
Почему одну? Я имею в виду запустить одну celery-таску, в нем взять eventloop и запустить таски (не celery), дождаться завершения через asyncio.gather. Они работают асинхронно. celery-таска запускается все равно в отдельном процессе (prefork), eventloop ни с кем не шарится.
Я имею в виду запустить одну celery-таску, в нем взять eventloop и
запустить таски (не celery), дождаться завершения через asyncio.gather
То есть одна таска селери на воркер. Эффективность. Вы перечёркиваете все преимущества asyncio
Они работают асинхронно. celery-таска запускается все равно в отдельном процессе (prefork), eventloop ни с кем не шарится.
Именно. Все преимущества asyncio
перечёркнуты
Есть обходной путь -- celery-pool-asyncio. Но это дикий костыль
Но.. В celery и так всегда одна таска на воркер! :) В классическом режиме, через prefork-пул, по крайней мере. Я не использую потоки, а eventlet - совершенно непредсказуемая штука и часто ломает остальные библиотеки (как было с openssl).
Если вы говорите про запуск celery-тасков через asyncio - да, этого нет и неизвестно будет ли вообще. Сначала, года 3 назад, обещали в версии 5, потом обещание переместилось в версию 6.
Однако, запускать asyncio внутри воркера вполне можно и нужно. У меня довольно крупные таски - например, скачать 50 гигабайтных файлов и объединить в один - прекрасно качаются все параллельно.
Но.. В celery и так всегда одна таска на воркер! :)
Аргументация в стиле:
-- Но позвольте, вы творите технический абсурд
-- Все так делают :)
У меня довольно крупные таски - например, скачать 50 гигабайтных
файлов и объединить в один - прекрасно качаются все параллельно.
Идея разделения на таски в том, что в случае ошибки мы всегда можем восстановить прогресс с минимальными потерями. Ваш подход предполагает написание своего менеджера загрузок
Вообще говоря мы начали с вашего утверждения о том как все плохо с asyncio и я только уточнил что не все там плохо. Но если вы хотите научить меня как скачивать и склеивать файлы - я не против узнать ваши рекомендации.
Celery всегда был синхронным и всегда в воркере выполнялась ровно одна таска (если без eventlet/greenlet). В общем-то, основная задача таких обработчиков и была - взять все CPU-bound таски и выполнять где-то в бэкграунде. Asyncio совсем не поможет если вы запускаете обсчет матрицы или какую-нибудь ML-задачу.
я только уточнил что не все там плохо
Да, а фласк позволяет запускать event loop в каждой вьюхе. Значит ли это, что во фласке "не все там" плохо с асинхронностью? Да кому она нужна в таком виде?
Celery всегда был синхронным и всегда в воркере выполнялась ровно одна таска (если без eventlet/greenlet).
У вас чёрный пояс по взаимоисключающим параграфам. Оруэлл одобряет. Помимо перечисленных вами, селери поддерживает другие пулы, и кроме перечисленных я знаю ещё про threadpool-executor.
Я даже не знаю, как так можно в одном предложении опровергнуть себя же?
взять все CPU-bound таски
Отсебятина.
Asyncio совсем не поможет если вы запускаете обсчет матрицы или какую-нибудь ML-задачу
Ещё один интересный парадокс. Когда в собственном проде мы качаем/клеим файлы (IO), отправляем почту и вебхуки (IO) или процессим транзакции (IO), вы аппелируете к CPU-bound задаче. То есть как бы и да -- asyncio на CPU-bound бесполезен. Но и как бы и нет -- большинство задач IO-bound, включая ваш собственный пример
Celery: проясняем неочевидные моменты