惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
博客园 - 【当耐特】
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
D
Docker
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
The Cloudflare Blog
雷峰网
雷峰网
A
About on SuperTechFans
小众软件
小众软件
博客园 - Franky
博客园 - 聂微东
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
MongoDB | Blog
MongoDB | Blog
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX
Engineering at Meta
Engineering at Meta
宝玉的分享
宝玉的分享
aimingoo的专栏
aimingoo的专栏
量子位
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
罗磊的独立博客
Martin Fowler
Martin Fowler
D
DataBreaches.Net
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Secure Thoughts
Project Zero
Project Zero
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tailwind CSS Blog
S
Schneier on Security
Blog — PlanetScale
Blog — PlanetScale
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
Security Latest
Security Latest
NISL@THU
NISL@THU
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
J
Java Code Geeks

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Celery Autoscale: что в лоб — то по лбу?
okolobackend · 2026-05-03 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение9 мин

Охват и читатели1.2K

Моей первой большой самостоятельной работой программиста была инвентаризация celery-задач. Нам с товарищем по бэкенду достался легаси-проект товарно-учетного приложения. С горем пополам перевезли его из Hetzner в родное «облако» и поняли, что срочно необходимо всё документировать, очищать и структурировать. Пока коллега упаковывал приложение в контейнеры, я занялся Celery, так как на этой библиотеке было завязано много бизнес-логики.

Пока группировал и отлаживал задачи, определял им очереди, нашел в документации загадочное autoscale. Кажется, что в тот момент этот параметр светился золотом. Вот оно! То, что нужно! Сейчас там как всё наладится и заработает без сучка и задоринки. Ровно, чинно, благородно.

Мне повезло, что так и случилось, очереди стали более спокойными. Причин тому несколько:

  • было достаточно ресурсов сервера;

  • задачи были, в основном, I\O-bound;

  • в процессе работы избавился от некоторых утечек памяти и ограничил время исполнения самых «отмороженных» задач.

Спустя время я решил отрефлексировать и пересмотреть тот опыт и был удивлен тому, как autoscale работает в действительности на разного рода очередях. Если у вас есть сомнения, стоит ли читать статью, то предлагаю решить загадку:

1. Запускаем воркер:

    `-A celery_app worker --autoscale=4,0 --worker_prefetch_multiplier=1`

2. Запускаем скрипт:
    `for idx_task in range(1, 601):
        io_task.delay()
        if idx_task % 4 == 0:
            time.sleep(1.7)`
3. Который генерирует такие задачи:
    `@celery.task(name='io')
    def io_task() -> int:
        result = 0
        for i in range(10**7):
            result += i**2
        time.sleep(1)
        return result`

Вопрос: сколько всего процессов будет создано за время обработки 600 задач?

Варианты ответа:
1. 31
2. 4
3. 150
4. 0

Если выбрали второй вариант — 4 процесса, то мне есть, чем вас удивить. Правильный ответ будет позже.

О понятиях

Воркер — экземпляр Celery, включающий в себя процесс-супервизор и все дочерние процессы.

Супервизор — ведущий процесс воркера, устанавливающий соединение с брокером и порождающий и управляющий прочими рабочими процессами. Сам задачи не обрабатывает.

Рабочий процесс — дочерний процесс супервизора внутри воркера для обработки задач. Создан или при старте воркера(concurrency), или динамически(autoscale).

Очередь по расписанию — очередь, в которой показатель Total(RabbitMQ) в любой момент времени не превышает количество рабочих процессов.

Нагруженная очередь — очередь, которая может иметь задачи в статусе Ready(RabbitMQ) и Total больше количества рабочих процессов.

Prefork autoscale

Для тех, кто не знаком с Python, Celery — распределенная очередь задач, работающая через брокер сообщений. Использует собственную библиотеку(billiard, форк от стандартной питоновской) для механизма мультипроцессинга. Prefork — это пул по умолчанию и по совместительству самый распространенный режим, к которому применим autoscale. Хорош для CPU-bound да и для прочих, так как не требует сторонних библиотек, в отличие от многопоточных.

Параметр autoscale задаётся при старте воркера --autoscale=max,min и весь жизненный цикл проходит между этих границ. Воркеру каждую секунду необходимо проверять всем ли условиям на настоящий момент он соответствует. Механизм autoscale[1] запускается в двух местах:

  1. Это собственный цикл body() с методом maybe_scale() класса Autoscaler, который крутится и смотрит:

    • есть ли что в очереди?

    • можно ли добавить рабочих процессов?

  2. Это callback при получении сообщения от брокера.

А вот демасштабирование работает по расписанию и лишь когда с последнего scale_up прошло более 30 секунд, значение по умолчанию для AUTOSCALE_KEEPALIVE.

В чем подвох загадки? В AUTOSCALE_KEEPALIVE и минимальном количестве процессов(их вовсе нет). Каждые 1.7 секунд четыре задачи(по штуке на рабочий процесс) попадают в очередь. Воркер их подхватывает, создает дочерние процессы и раздает им задачи. Важно, что AUTOSCALE_KEEPALIVE отсчитывается от последнего scale_up(). Время на обработку задачи примерно от 1.6 до 2.2 секунды, то есть пауза в цикле(1.7) настроена так, чтобы воркер закончил обработку, взял новую партию задач и очередь была +/- пустой. Плюс, казалось бы, пренебрежительные миллисекунды на публикацию сообщений и IPC.

Но по итогу нам это дает следующее: каждый рабочий процесс подходит к порогу AUTOSCALE_KEEPALIVE, выполнив примерно 15 задач(значение взято из логов) и очень может быть, что сейчас ждет новую. Но цикл maybe_scale(), глядя на пустую очередь и простаивающий процесс, считает его лишним и «сворачивает».

Схематично это выглядит так(тайминги условны).

Но следом поступают задачи. И мы вынуждены снова создавать рабочие процессы. И так повторяется практически каждые 30 секунд.

В логе выглядит так

[2026-04-21 09:52:14,481: INFO/MainProcess] Task cpu_intensive[f30f03c9-5c03-4f9a-a28b-6c5624549b7c] received
[2026-04-21 09:52:14,482: INFO/MainProcess] Scaling up 1 processes.
[2026-04-21 09:52:14,524: INFO/MainProcess] Task memory_intensive[c88643c5-d9b2-4014-a79e-bb1564b481c7] received
[2026-04-21 09:52:14,525: INFO/MainProcess] Scaling up 1 processes.
[2026-04-21 09:52:14,571: INFO/MainProcess] Task cpu_intensive[47e0d170-ad7c-44fb-a401-40f3a1be46bb] received
[2026-04-21 09:52:14,571: INFO/MainProcess] Scaling up 1 processes.
[2026-04-21 09:52:14,635: INFO/MainProcess] Task cpu_intensive[abedebc8-05a6-400e-bb98-4062f3633ddf] received
[2026-04-21 09:52:14,636: INFO/MainProcess] Scaling up 1 processes.
...
[2026-04-21 09:52:57,543: INFO/MainProcess] Scaling down 1 processes.
...
[2026-04-21 09:52:57,543: INFO/MainProcess] Task cpu_intensive[2ff56d89-ca89-4edf-b557-a9465b8d4f72] received
[2026-04-21 09:52:57,543: INFO/MainProcess] Scaling up 1 processes.

Здесь и кроется причина, что ответ не четыре, а 31. Четыре процесса за полный цикл работы в описанных условиях возможны при AUTOSCALE_KEEPALIVE=600.

Правильный ответ — 31.

Отмечу, что разброс может быть до 34 процессов: зависит от «железа» и момента. У меня задача считалась от 1.58 до 1.92 сек

Рассчитать максимум рабочих процессов можно так:

(общая длительность работы / AUTOSCALE_KEEPALIVE) * кол-во динамических процессов + минимальный порог

По условию загадки общая длительность работы равна 255 секунд((600(всего задач) / 4(размер пачки)) * 1.7 секунд сна)

Подставив в формулу значения (255/30) * 4 + 0 получим 34. Если бы половина процессов была статической, то вышло бы (255/30) * 2 + 2 = 19. Почему: а) два любых процесса всегда живы; б) два процесса могут заменяться, но не чаще чем раз в полминуты.

На графике в брокере это может выглядеть так:

  • левая сторона с пиками(пример нагруженной очереди), здесь autoscale будет трудно хулиганить с порождением процессов;

  • для правой же стороны(пример очереди по расписанию) ситуация становится обратной.

Казалось бы! А вона оно как.

На эту тему есть открытый вопрос в репозитории фреймворка[2]. Возможно, прунинг процессов будет отталкиваться не от последнего скейла, а от последнего сообщения. Стоит ли менять значение по умолчанию? Для микрозадач, длительностью до 2 секунд, и не нагруженной очереди, скорее да. Но при прочих условиях вы сделаете concurrency.

Prefork concurrency

В сравнении с autoscale concurrency — «скучная» технология: какой лимит задан при запуске столько рабочих процессов и будет работать всю жизнь воркера(если лимит не задан, то по умолчанию использует кол-во ядер). У него нет специальных циклов для проверки всем ли параметрам он соответствует, его ценят таким, какой он есть. И в том же количестве. Исключением из этого правила могут стать специальные аргументы, используемые при настройке инстанса Celery. Или форс-мажоры типа падения воркера. Впрочем, эти же факторы распространяются и на autoscale

Я не буду подробно останавливаться на всем многообразии параметров, упомяну лишь те, что непосредственно влияют на тему статьи. Это --max-tasks-per-child и --max-memory-per-child. Если с первым из названия можно понять, что это ограничение на общее количество выполненных задач дочерним процессом, то у второго параметра есть любопытная особенность, на мой взгляд, неочевидная: --max-memory-per-child накладывает ограничения по затраченной памяти не в рантайме, а на «жизнь» самого процесса, то есть если вы настроили 100 MB, а задача потребила 120 MB, то после выполнения процесс будет заменён новым[3]. Причем память все равно может утекать, так как исчерпание предела проверяется после выполнения задачи; внутри процесса же — можно доработаться и до OOM Killer. Поэтому эта настройка может выйти боком и процессы будут пересоздаваться чаще, чем требуется.

Runtime

Давайте же посмотрим, как с подобными загадке задачами будет справляться celery в обозначенных режимах. Я подготовил сводные таблицы с фиксированными и динамическими рабочими процессами, отображающую производительность, за которую мы можем побороться этими инструментами. Увидим сколько рабочих процессов будет обслуживать один цикл и как меняются скорость обработки одной задачи от постановки до результата и общая пропускная способность. И есть ли вообще разница.

Что такое производительность?

В настоящем контексте мы можем рассматривать 4 вида:

  • Пропускная способность(throughput), кол-во задач в секунду;

  • Обработка одной задачи(latency), сек;

  • Обработка N задач (общее время), сколько времени займет разбор фиксированной пачки;

  • «Шумный» сосед, отъём ресурсов и, как следствие, снижение работоспособности других процессов.

Упор будет на throughput и latency, так как а) фиксировано время скрипта(для 3 пункта не подойдет); б) нужно отдельно контролировать какой-то важный процесс(для соседа), что увеличивает сложность эксперимента.

Рабочее окружение

Все замеры проведены с версией celery 5.6.3, на ноутбуке с процессором AMD Ryzen 5 5500U with Radeon Graphics × 6 в консоли Linux Mint 22.3 - Cinnamon 64-bit.

С помощью cgroups и cpuset ограничил эксперимент двумя ядрами(первые потоки): 5 и 6. Некая имитация отдельного 2х-ядерного сервера.

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

Методика

Каждые 1.6(по расписанию — 10) секунд в брокере публикуются задачи(I/O и memory-bound, нормальный runtime которых 1.7 сек) в количестве равным максимальному кол-ву рабочих процессов. Для autoscale нижним порогом является половина от максимума. К примеру, если concurrency=4, то в паре будет autoscale=4,2. Каждый рабочий процесс ограничен worker_prefetch_multiplier=1, то есть может за раз взять одну задачу. Длительность одного замера 300 секунд с перезапуском воркера. Каждый вариант(2 очереди Х 2 режима Х 3 кол-в процессов) по 20 раз.

Все 240 замеров были проведены в случайном порядке.

Нагруженная очередь

Режим

Ср. процессов*

Длительность (с)

Задач

Throughput (з/с)

Сред. latency (с)

CV latency

95% ДИ для среднего

Медиана (с)

90-й перц. (с)

95-й перц. (с)

autoscale(2,1)

2.90

303.94

363.8

1.20

6.33

74.0%

[4.14 – 8.51]

5.44

8.13

8.90

concurrency(2)

2.00

303.93

366.3

1.21

5.22

4.5%

[5.11 – 5.33]

5.22

7.78

8.15

autoscale(4,2)

7.50

303.99

716.0

2.36

8.65

65.5%

[6.00 – 11.29]

7.57

12.52

14.56

concurrency(4)

4.00

303.91

726.0

2.39

6.63

14.0%

[6.20 – 7.06]

6.61

9.91

10.85

autoscale(8,4)

11.40

302.71

1281.2

4.23

22.42

4.1%

[22.00 – 22.85]

21.97

39.15

41.52

concurrency(8)

8.00

302.73

1281.2

4.23

22.55

9.7%

[21.53 – 23.57]

22.02

38.71

41.27

Очередь по расписанию

Режим

Ср. процессов*

Длительность (с)

Задач

Throughput (з/с)

Сред. latency (с)

CV latency

95% ДИ для среднего

Медиана (с)

90-й перц. (с)

95-й перц. (с)

autoscale(2,1)

11.00

302.65

60.0

0.20

1.67

0.2%

[1.67 – 1.67]

1.65

1.78

1.79

concurrency(2)

2.00

302.65

60.0

0.20

1.65

0.2%

[1.65 – 1.66]

1.65

1.68

1.72

autoscale(4,2)

22.00

302.68

120.0

0.40

1.69

0.7%

[1.69 – 1.70]

1.68

1.76

1.88

concurrency(4)

4.00

302.68

120.0

0.40

1.66

0.2%

[1.66 – 1.66]

1.65

1.69

1.74

autoscale(8,4)

43.75

302.74

240.0

0.79

1.87

0.5%

[1.87 – 1.88]

1.85

2.07

2.15

concurrency(8)

8.00

302.75

240.0

0.79

1.89

7.9%

[1.82 – 1.95]

1.80

2.09

2.28

* - среднее количество процессов созданных одним воркером за один прогон 300 секунд

Малые выводы о prefork autoscale

Когда я впервые взялся за эту тему, то первым тезисом, который собирался отстаивать, был «Остановите autoscale! Он убивает систему и latency». И таблицы выше на первый взгляд это подтверждают.

  1. Autoscale в нагруженной очереди может быть нестабилен. Его ДИ выходит за «приемлемые» пределы.

  2. Средний latency на 30%, а медианный на 14% хуже concurrency для 4-процессного воркера.

  3. Чем больше динамических процессов в очереди по расписанию, тем заметнее разница медианного latency между autoscale и concurrency в пользу второго. Хоть она и не критична.

А с другой стороны множество форков не сильно влияет на пользовательский опыт, что демонстрирует autoscale в очереди по расписанию или нагруженной очереди с 8 процессами.

Стоит ли отказываться от autoscale? Если у вас есть постоянно нагруженная очередь, то concurrency скорее всего будет лучшим решением. По крайней мере вы можете себя избавить от лишних раздумий и поисков скрытой угрозы при неконтролируемом обновлении процессов. С другой же стороны для задач по расписанию можно настроить «призрачный» воркер. Есть задачи — есть процессы.

Надеюсь, статья станет для вас хорошим подспорьем для проведения инвентаризации собственных celery-задач.

В качестве заключения

Изначально статья называлась Что в лоб — то по лбу и точка. Но при сборе метрик я сменил гнев и поспешные выводы на милость и обоснованные решения. Поэтому заменил точку на вопросительный знак.

Я признаю ограничения, которые мешают делать широкие и далеко идущие выводы. Для ЦПУ-цепких задач, где процессор всегда много занят, форки могут оказать негативное влияние. Для двух потоков на одном ядре, я получал обратные данные, и размах был велик. А когда я не ограничивал ядра и процессы кочевали по всему железу, тогда autoscale проигрывал на 5-10% и в latency, и в пропускной способности. Но истина всегда конкретна: был выбран конкретный пример с конкретными ограничениями и данные изменились.

Я не стал описывать принципы работы Celery с архитектурными особенностями, иначе бы вышло громоздко и отвлекло от темы. Многообразие настроек, распределение по очередям, предвыборка и «голод» процессов — это всё влияет скорость и качество обработки. Если будет интересно — следующей разберу архитектуру фреймворка; также планирую охватить темы Canvas Workflows, масштабирования для gevent/eventlet и docker/K8s. А может быть пройтись по очередям и принципам их создания, ведь порой проблемы не в том, как работает механизм, а с чем и в какой последовательности.

Источники

  1. Celery Autoscaling: Scaling Decision Flowchart — https://deepwiki.com/celery/celery/5.6-autoscaling#scaling-decision-flowchart

  2. Issue #8943: Autoscale should only scale down if no tasks were accepted during keepalive period — https://github.com/celery/celery/issues/8943

  3. Billiard Worker Process Lifecycle — https://deepwiki.com/celery/billiard/2.2-worker-process-lifecycle#the-work-loop

Исходный код эксперимента: https://github.com/okolobackend/Celery-Architecture-and-Scaling