Celery - это асинхронная очередь задач / очередь заданий, основанная на распределенной передаче сообщений. Понимать, что такое синхронное / асинхронное программирование. Важно понимать сельдерей. В разделе ниже это объясняется. Если вы уже знаете это, вы можете перейти к разделу Когда его использовать? или сразу перейти к разделу Сельдерей.

Синхронный и асинхронный код.

В этом вопросе в stackoverflow пользователь themightysapien провел отличную аналогию для объяснения синхронного и асинхронного кода:

Синхронное выполнение

Мой босс очень занятой человек. Он говорит мне написать код. Я ему говорю: хорошо. Я начинаю, а он смотрит на меня, как стервятник, стоящий позади меня, с моего плеча. Я говорю: «Чувак, черт возьми, почему бы тебе не пойти и не заняться чем-нибудь, пока я закончу это?»

он такой: "Нет, я жду здесь, пока ты не закончишь". Это синхронно.

Асинхронное выполнение

Босс велит мне это сделать, и вместо того, чтобы сразу же ждать моей работы, босс уходит и выполняет другие задачи. Когда я заканчиваю свою работу, я просто докладываю своему боссу и говорю: «Я СДЕЛАНО!» Это асинхронное выполнение.

Асинхронный код - это фрагмент кода, который выполняется независимо и отделен от потока выполнения программы. Мы используем это, когда не хотим блокировать основной поток выполнения программы.

Вы могли подумать: - Хорошо, я понял! но какого черта я хочу или должен это делать ???

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

Когда это использовать?

Пример 01: регистрация

Представим, что у нас есть веб-сайт, и мы разрабатываем функцию для регистрации. В процессе регистрации мы должны:

проверить учетные данные пользователя;

хранить информацию о пользователе в базе данных;

отправить электронное письмо с подтверждением;

SMTP-серверу, отвечающему за отправку электронной почты, иногда требуется 3, 4 или даже 6, 7 секунд. Для начала использования платформы подтверждение пользователя не требуется. Мы не хотим заставлять их так долго ждать, смотря утомительный экран загрузки. За это время пользователь мог отказаться от регистрации. В этом случае нам нужно сделать все синхронно, кроме электронной почты. Мы просто положим почту в ящик, чтобы доставить ее позже. Проверьте фрагмент ниже.

Только функция start_to_send_confirmation_email должна быть асинхронной. Во время выполнения интерпретатор перейдет со строки 3 на строку 4 перед отправкой электронного письма. Фрагмент кода из функции start_to_send_confirmation_email будет выполнен отдельно от этого потока. Пользователь получит ответ до отправки электронного письма.

Пример 02: Финансовый отчет

Финансовый аналитик нажимает кнопку, чтобы увидеть результаты за месяц. Это займет некоторое время, и аналитик не хочет ждать долгого и утомительного экрана загрузки, чтобы увидеть результаты, он хочет продолжать использовать платформу и проверять результаты позже, когда они будут готовы.

Как разработчик, вы не хотите, чтобы запросы ожидали обработки в течение минут или даже часов. На самом деле у этого запроса есть отличный шанс достичь пределов тайм-аута вашим веб-сервером или провайдером DNS (черт возьми, Cloudflare).

- Хорошо, теперь я знаю, что такое асинхронный код и когда мне следует его использовать. Но как я могу это сделать на Python?

Для этого мы можем использовать модуль потока Python и делать это вручную или использовать задание типа Celery.

Сельдерей

Принцип очень прост: одна (или несколько) программ добавляют задачи в очередь на выполнение. Эта очередь также известна как Посредник сообщений. Celery - это не просто библиотека, она работает в другой службе, чем приложение, например в базах данных, серверах SMTP и т. Д. Эта служба отслеживает очередь и каждый раз добавляется новая задача, сельдерей выполняет ее.

Задача сельдерея во многих случаях представляет собой сложный код, для выполнения которого требуется мощная машина. Как я уже говорил, сельдерей работает в сервисе, отделенном от вашего приложения, что означает, что вы можете запускать его на отдельной машине и иметь столько очередей, сколько захотите. Это очень помогает масштабировать приложение.

Наше первое приложение для сельдерея

Мы собираемся создать наше первое приложение для сельдерея. Это должно быть простым и сосредоточенным на понимании концепции сельдерея.

Предварительные условия:

Мы будем использовать Redis в качестве брокера сообщений. По сути, брокер сообщений организует очередь, это абстракция. У Celery нет намерения организовывать очереди, он просто выполняет задачи.

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

  • Создайте файл бизнес-логики с именем first_app.py;
  • Создайте папку с названием celery_stuff;
  • Внутри папки celery_stuff создайте файл __init__.py;
  • Внутри папки celery_stuff создайте файл tasks.py;

Дерево вашего проекта должно выглядеть так:

├── celery_stuff
│ ├── __init__.py
│ └── tasks.py
└── first_app.py

Давайте создадим функцию для асинхронного выполнения задачи сельдерея в first_app.py. Обратите внимание, что start_serve_a_beer - это обычная функция синхронизации, созданная нами. serve_a_beer.delay () помещает задачу в очередь (брокер сообщений) для выполнения службой сельдерея. Задача serve_a_beer еще не существует и будет создана на следующих шагах.

Теперь в celery_stuff / tasks.py создайте экземпляр приложения celery, задачу serve_a_beer и зарегистрируйте его для приложение для сельдерея.

Бег

Перед запуском нашего приложения нам нужно запустить службу сельдерея, потому что при запуске first_app.py код добавит задачу в очередь (строка 11), а если служба сельдерея не запущена задача не будет выполнена.

Бегущий сельдерей

$ celery -A celery_stuff.tasks worker -l debug

Запуск первого приложения

$ python first_app.py

Если все в порядке, вы должны увидеть это в журналах сельдерея:

Работа с несколькими задачами

Вернемся к celery_stuff / tasks.py и добавим новую задачу под названием serve_a_coffee.

В файле first_app.py импортируем новую задачу с именем serve_a_coffee и запустим их. Теперь файл должен выглядеть так.

Снова запустите сельдерей и first_app.

$ celery -A celery_stuff.tasks worker -l debug

$ python first_app.py

Обе задачи должны быть выполнены.

Работа с несколькими очередями

Представьте себе этот код в производственной среде, выполняющий тысячу задач в минуту. Конечно, эти задачи очень похожи, но представьте, что задача serve_a_beer самая медленная и сложная, чем serve_a_coffee. Процесс приготовления кофе действительно прост, вам понадобится вода, кофе и фильтр! Но, чтобы сделать пиво, вам понадобится много ингредиентов и подождать минимум месяц! Если у вас разные функции, разумно разделить их на разные очереди. Таким образом, вы можете выбрать разные машины для выполнения этих разных задач.

Определение очередей

Мы не определили очередь. Итак, задачи будут отправлены в очередь сельдерея по умолчанию. Пиво и кофе стояли в очереди вместе. Это плохо, потому что каждый раз, когда делается много пива, кофе придется долго ждать.

Давайте изменим код, чтобы разделить наши задачи на определенные очереди. В файле celery_stuff / tasks.py настройте маршруты в приложении. В конфигурации task_routes мы можем указать очередь для каждой задачи.

Запуск сельдерея в разных очередях!

В предыдущем разделе мы запускали 2 сервиса:

  • Служба приложений
  • Сервиз из сельдерея

Теперь запустим 3 сервиса:

  • Служба приложений
  • Сервиз из сельдерея для serve_a_beer
  • Еще один сервис Celery для serve_a_coffee

Выполните приведенные ниже команды, чтобы настроить их все;

$ python first_app.py

$ celery -A celery_stuff.tasks worker -l debug -Q beer

$ celery -A celery_stuff.tasks worker -l debug -Q coffee

Мы использовали аргумент -Q, чтобы указать очередь. Если бы у нас было 10 разных очередей, мы могли бы запустить службу сельдерея для каждой из них!

Вы, конечно, можете использовать одну и ту же службу сельдерея для многих очередей, сколько захотите. Это очень часто встречается в режиме разработки.

$ celery -A celery_stuff.tasks worker -l debug -Q пиво, кофе

Вам лень делать пошагово и все устанавливать? Просто клонируйте репозиторий на github и запускайте с помощью docker.

Сначала измените строку 4 в celery_stuff / first_app.py на:

Теперь просто запустите контейнеры.

$ docker-compose run --build

Вы должны увидеть в журналах пиво и кофе!

Вывод

Сельдерей - хороший вариант для выполнения асинхронных задач на Python. Он распространен, прост в использовании и масштабируется. В этой статье мы узнали, что такое приложение для сельдерея, как создавать задачи, как направлять задачи в разные очереди и как запускать службы сельдерея в определенные очереди. Сельдерей может немного расстраивать на первых этапах, особенно из-за некоторых пробелов в документации, но он очень прост в использовании и устраняет множество сложностей. Надеюсь, я заполнил некоторые из этих пробелов, особенно для первых шагов!