Модуль 35

Розгортання Celery у production

Ось готовий урок, створений спеціально за твоїм майстер-промптом. Вмикай уяву — ми в аудиторії, і я стою перед тобою на сцені!


🎓 CS50: Розгортання Celery у Production

Привіт, друзі! Радий бачити вас. Це — CS50... ну, майже.

Сьогодні ми поговоримо про річ, яка перетворює ваш "домашній проект" на справжню "бойову систему". Ми вже знаємо, як писати задачі для Celery. Ми запускали celery worker у терміналі, бачили, як магія відбувається, і задоволено йшли пити каву.

Але стривайте.

Що станеться, якщо ви закриєте вікно терміналу? Що буде, якщо сервер перезавантажиться? Правильно — магія зникне. Ваші фонові задачі зупиняться, листи не відправляться, а звіти не згенеруються.

Сьогоднішня тема — Розгортання (Deployment) Celery у production. Ми навчимося робити так, щоб наш воркер жив вічно (або майже вічно). Поїхали!


1. 🔥 Вступ: Чому просто celery worker — це погана ідея?

Уявіть, що ви відкрили піцерію. У вас є касир (ваш веб-сервер, наприклад, Django або FastAPI), який приймає замовлення. І є кухар (Celery), який пече піцу на кухні.

Поки ви в ресторані й дивитеся на кухаря, він працює. Але як тільки ви виходите з приміщення (закриваєте термінал SSH), кухар знімає фартух і йде додому. А замовлення продовжують надходити! Клієнти нервують, каса переповнюється (черга в Redis росте), а піци немає.

Риторичне питання: Ви б довірили свій бізнес кухарю, який працює тільки тоді, коли ви дивитесь йому в потилицю? Звісно, ні.

Нам потрібен Менеджер ресторану. Суворий, відповідальний, який: 1. Запустить кухаря на зміну автоматично, як тільки відкриється ресторан (запуск при старті системи). 2. Якщо кухар раптом знепритомніє або впаде — наллє йому води й змусить працювати далі (автоматичний рестарт при падінні). 3. Веде журнал подій (логування), щоб ми знали, що відбувалося, поки нас не було.

У світі Linux роль цього менеджера найчастіше виконує система ініціалізації systemd (або Docker у контейнеризованому світі).


2. 🧠 Теоретична база: Що там "під капотом"?

Давайте розберемося, що таке "демонізація" (daemonization), не лякаючись цього слова.

Що таке демон?

Ні, це не містична істота. У Linux демон — це процес, який працює у фоновому режимі, не прив'язаний до вашого терміналу. Веб-сервер (Nginx), база даних (PostgreSQL) — це все демони. Ми хочемо зробити Celery демоном.

Systemd — наш головний менеджер

Більшість сучасних Linux-серверів (Ubuntu, Debian, CentOS) використовують systemd. Це програма, яка керує іншими програмами.

Як це працює: Ви створюєте спеціальний файл-інструкцію (Unit file) з розширенням .service. У ньому ви кажете systemd:

"Гей, ось команда запуску Celery. Запускай її від імені користувача ubuntu. Якщо вона впаде — підніми її. Логи пиши туди-то".

Ключові поняття (Це треба зрозуміти):

  1. Concurrency (Конкурентність): Скільки "рук" має ваш кухар. За замовчуванням Celery створює стільки процесів, скільки у вас ядер процесора. У production це треба налаштовувати.
  2. Graceful Shutdown (М'яка зупинка): Коли ми перезавантажуємо сервер, ми не хочемо "вбивати" задачу посеред виконання. Ми хочемо дати їй час закінчити. Systemd вміє посилати сигнал "закругляйся" (SIGTERM), а Celery вміє його розуміти.

3. 🧪 Приклади: Від "на колінці" до PRO

Приклад 1: "Студентський метод" (Не робіть так у production!)

Ви заходите на сервер і пишете:

nohup celery -A proj worker -l info &

Що ви очікуєте? Що воно працюватиме у фоні. Що буде насправді? Воно працюватиме. Але якщо процес впаде — він не підніметься. Якщо сервер перезавантажиться — Celery не запуститься. Логи перемішаються. Це — хаос.


Приклад 2: "Золотий стандарт" (Systemd)

Ось як це роблять дорослі дядьки й тітоньки. Ми створимо файл сервісу.

Файл: /etc/systemd/system/celery.service

[Unit]
Description=Celery Service
After=network.target

[Service]
Type=forking
User=ubuntu
Group=ubuntu
EnvironmentFile=/etc/conf.d/celery
WorkingDirectory=/home/ubuntu/myproject
ExecStart=/bin/sh -c '${CELERY_BIN} multi start w1 -A ${CELERY_APP} --pidfile=${CELERY_PID_FILE} --logfile=${CELERY_LOG_FILE} --loglevel=${CELERY_LOG_LEVEL}'
ExecStop=/bin/sh -c '${CELERY_BIN} multi stopwait w1 --pidfile=${CELERY_PID_FILE}'
ExecReload=/bin/sh -c '${CELERY_BIN} multi restart w1 --pidfile=${CELERY_PID_FILE}'
Restart=always

[Install]
WantedBy=multi-user.target

Розбір польотів: * User=ubuntu: Ніколи не запускайте Celery від root! Це дірка в безпеці. * Restart=always: Якщо впаде — підняти негайно. * multi start: Це спеціальна команда Celery для запуску демонів.

Після створення файлу ми робимо магічні паси руками в терміналі:

sudo systemctl daemon-reload  # Systemd, прочитай нові інструкції!
sudo systemctl enable celery  # Стартуй автоматично при включенні сервера!
sudo systemctl start celery   # Запусти прямо зараз!

Приклад 3: Сучасний підхід (Docker)

Якщо ви використовуєте Docker, то Systemd вам не потрібен всередині контейнера. Вашим менеджером стає Docker (або Kubernetes).

Файл: docker-compose.yml

version: '3.8'
services:
  worker:
    build: .
    command: celery -A proj worker -l info
    restart: always  # <-- Ось ваш "менеджер", який підніме контейнер
    depends_on:
      - redis

Чому це простіше? Бо Docker бере на себе ізоляцію та перезапуск. Але логіка та сама: процес має бути керованим ззовні.


4. 🛠 Практична частина

Час закачати рукави. Виконайте ці завдання, щоб закріпити знання.

🔹 Завдання 1: Створення сервісу Напишіть celery.service файл для вашого проекту. Але уявіть, що ваш проект лежить у папці /var/www/shop. Який шлях ви вкажете у WorkingDirectory?

🔹 Завдання 2: "А що, якщо..." (Експеримент) Запустіть Celery через systemd. Потім знайдіть ID процесу (через ps aux | grep celery) і "вбийте" його командою kill -9 <PID>. Перевірте статус через sudo systemctl status celery. Що сталося? Він воскрес?

🔹 Завдання 3: Логи — наше все Налаштуйте сервіс так, щоб логи писалися не в стандартний вивід, а у файл /var/log/celery/worker.log. Підказка: Вам знадобиться параметр --logfile і права на запис у папку для користувача.

🔹 Завдання 4: Міні-кейс (Масштабування) У вас дуже важкі задачі (наприклад, обробка відео). Один воркер не справляється. Змініть конфігурацію systemd або docker-compose так, щоб запустити воркер з параметром --concurrency=4 (4 потоки).

🔹 Завдання 5: Помилка новачка Ви створили сервіс, але він падає з помилкою Permission denied при спробі створити PID-файл. Чому це сталося і як це виправити? (Думайте про права доступу користувача, якого ви вказали у User=).


5. 💡 Мислення як у розробника

Як відрізнити новачка від профі при розгортанні Celery?

  1. Новачок запускає Celery від root.

    • Чому це погано: Якщо хтось зламає ваш воркер (наприклад, через Pickle-серіалізацію), він отримає повний доступ до сервера.
    • Як думає профі: "Principle of Least Privilege". Даємо мінімальні права.
  2. Новачок ігнорує моніторинг.

    • Ситуація: Черга забилася 10 000 завданнями, клієнти скаржаться, а ви дізналися про це через 2 дні.
    • Як думає профі: Він ставить Flower (веб-інтерфейс для Celery) або налаштовує алерти в Prometheus/Grafana. "Якщо я не бачу пульсу пацієнта, я вважаю його мертвим".
  3. Новачок забуває про пам'ять.

    • Проблема: Python іноді погано звільняє пам'ять. Воркер працює місяць і "з'їдає" всю RAM.
    • Як думає профі: Він додає параметри --max-tasks-per-child. Це змушує воркера перезавантажуватися після виконання, скажімо, 1000 задач, очищуючи пам'ять. Це як "душ після зміни" для кухаря.

6. 🧩 Підсумок

Отже, що ми сьогодні зробили? Ми звільнили вас від необхідності сидіти біля терміналу. 1. Ми зрозуміли, що production вимагає надійності та автоматизації. 2. Ми навчилися використовувати Systemd (або Docker) як нашого "менеджера", який стежить за воркерами. 3. Ми тепер знаємо, як керувати логами та правами доступу.

Тепер ваша система працює автономно. Ви можете спати спокійно, знаючи, що ваші листи відправляються, а дані обробляються.

Тизер наступного уроку: Але що робити, якщо одна черга забита важкими задачами, а легкі задачі чекають у тій самій черзі і не можуть пробитися? Наступного разу ми поговоримо про Routing (Маршрутизацію) — як створити VIP-чергу для термінових завдань і окрему чергу для "важковаговиків".

Це був CS50. До зустрічі!