Ось твій урок у стилі CS50. Вмикаймо уяву, відкриваймо термінал, і поїхали! 🚀
🎓 Урок: Встановлення Celery та перший запуск
(або: Як навчити ваш код робити дві справи одночасно)
1. 🔥 Вступ: Чому ми взагалі тут?
Привіт, друзі! 👋
Уявіть ситуацію. Ви заходите на сайт, щоб завантажити свій звіт за рік. Натискаєте кнопку «Згенерувати PDF» і… чекаєте. Секунда. Дві. Десять. Браузер «завис», коліщатко крутиться. Ви не можете клікнути нікуди більше. Зрештою, сервер каже: "Timeout Error". Знайомо?
Питання до вас: Якби ви були власником кав'ярні, і клієнт замовив складний лате, чи змушували б ви всю чергу чекати, поки бариста малює сердечко на пінці, не приймаючи нових замовлень?
Звісно, ні! Ви б взяли замовлення, видали чек (номер замовлення) і крикнули баристі: "Один лате!", а самі продовжили б обслуговувати наступного клієнта.
У світі Python: * Ви (касир) — це ваш основний веб-додаток (Django/Flask). * Бариста — це Celery. * Дошка із замовленнями — це Брокер (Redis або RabbitMQ).
Без Celery ваш код працює синхронно: він не піде далі, доки не закінчить попередню задачу. Celery дозволяє сказати: "Зроби це пізніше, у фоні, а я пішов відповідати користувачу" .
Сьогодні ми навчимося наймати цього "баристу" для вашого коду.
2. 🧠 Теоретична база (Що там «під капотом»?)
Перш ніж писати pip install, давайте розберемося в архітектурі. Це критично важливо, щоб не писати код наосліп.
У схемі роботи Celery є три головні гравці. Запам’ятайте це тріо:
- Producer (Продюсер/Клієнт): Це ваш скрипт або веб-сайт. Він каже: "Треба відправити 1000 імейлів".
- Broker (Брокер/Посередник): Це поштова скринька або черга. Продюсер кидає туди задачу. Celery сам по собі не зберігає задачі, йому потрібна пам'ять. Зазвичай це Redis (найпростіше) або RabbitMQ.
- Worker (Робітник): Це процес Celery, який постійно дивиться на Брокера і питає: "Є щось для мене?". Як тільки з'являється задача — він її хапає і виконує.
💡 Інтуїтивне розуміння:
Коли ви викликаєте функцію в Celery, ви не запускаєте її. Ви відправляєте повідомлення брокеру: "Будь ласка, запусти цю функцію з такими аргументами, коли будеш вільний".
Важливо запам'ятати: * Celery — це не магія, це окремий процес. * Без Брокера (Redis) Celery не працюватиме. Вони як телефон і стільникова мережа.
3. 🧪 Приклади: Від «Hello World» до магії
Досить балачок. Давайте кодити.
Крок 0: Підготовка
Я припускаю, що у вас встановлений Python і запущений Redis.
(Якщо Redis немає, уявіть, що це просто програма, яка висить на порту 6379 і чекає повідомлень. Для старту на Docker: docker run -d -p 6379:6379 redis).
Встановлюємо бібліотеки:
pip install celery redis
Крок 1: Створення файлу tasks.py
Створимо файл, де житиме наш "бариста".
# tasks.py
from celery import Celery
import time
# Налаштовуємо Celery
# 'app' — назва нашого додатку
# broker — адреса нашого "посередника" Redis
app = Celery('my_first_app', broker='redis://localhost:6379/0')
# @app.task перетворює звичайну функцію на задачу Celery
@app.task
def add(x, y):
return x + y
@app.task
def heavy_task(name):
print(f"Починаю важку роботу для {name}...")
time.sleep(5) # Імітуємо довгий процес (наприклад, обробка відео)
print(f"Роботу для {name} завершено!")
return "Готово!"
Крок 2: Запуск воркера (Наймаємо баристу)
Відкрийте термінал у папці з файлом і запустіть:
celery -A tasks worker --loglevel=info
Ви побачите купу тексту (ASCII-арт Celery). Якщо пише "Connected to redis" — вітаю, ви в системі!
Крок 3: Виклик задачі (Робимо замовлення)
Питання: Якщо я зараз запущу Python-консоль і викличу heavy_task("David"), що станеться? Вона зависне на 5 секунд?
Ні! Дивіться сюди.
Відкрийте новий термінал (воркер хай працює в першому).
# Заходимо в python shell
>>> from tasks import heavy_task
# УВАГА: Ми викликаємо не heavy_task(), а heavy_task.delay()!
>>> result = heavy_task.delay("David")
# Консоль одразу повернула керування! Ніяких затримок.
>>> print(result)
<AsyncResult: 5b4e8d3-...>
Подивіться тепер у перший термінал (там, де Celery). Ви побачите:
Task tasks.heavy_task[...] received
...
Task tasks.heavy_task[...] succeeded in 5.0s: 'Готово!'
Що відбулося? Ви кинули задачу в Redis, Celery її підхопив, виконав, а ваш основний скрипт навіть не помітив навантаження. Це і є асинхронність.
4. 🛠 Практична частина
Тепер ваша черга. Не просто читайте — пишіть!
- 🔹 Завдання "Калькулятор":
Запустіть воркер. У консолі Python додайте два числа через
add.delay(4, 4). Перевірте логи воркера. - 🔹 Завдання "Пошта":
Напишіть нову задачу
send_email(email_address), яка "спить" 3 секунди і друкує "Email sent to...". Перезапустіть воркера (Celery треба перезапускати при зміні коду!). Викличте її. - 🔹 Експеримент "Черга":
В консолі запустіть
heavy_task.delay("User 1"), і одразу ж, швидкоheavy_task.delay("User 2"). Подивіться в логи. Вони виконуються паралельно чи послідовно? (За замовчуванням Celery запускає кілька процесів, тому, ймовірно, паралельно). - 🔹 Питання "А що, якщо?":
Зупиніть воркера (Ctrl+C). Відправте задачу через
.delay(). Вона не зникла, правда? Тепер запустіть воркера знову. Що сталося? (Спойлер: Вона виконається одразу після запуску. Redis зберіг її для вас!)
5. 💡 Мислення як у розробника
Як відрізнити новачка від профі при роботі з Celery?
Помилка новачка:
Передавати величезні об'єкти в .delay().
# ❌ ПОГАНО
user = User.objects.get(id=1)
send_welcome_email.delay(user) # Передаємо цілий об'єкт бази даних
Чому це погано? Поки задача дійде до воркера, дані користувача в базі можуть змінитись. А ще серіалізація об'єкта може бути складною.
Мислення профі: Передавати тільки ідентифікатори (ID).
# ✅ ДОБРЕ
user_id = 1
send_welcome_email.delay(user_id) # Воркер сам дістане свіжі дані з БД
Ще одна порада: Завжди питайте себе: "Чи можу я виконати цю задачу двічі?" (Ідемпотентність). Якщо воркер впаде і перезапустить задачу, чи не відправите ви клієнту гроші двічі? Код має бути готовим до цього.
6. 🧩 Підсумок
Отже, що ми сьогодні зробили:
1. Зрозуміли, що Celery — це спосіб не змушувати користувача чекати.
2. Дізналися про тріо: Producer -> Broker (Redis) -> Worker.
3. Навчилися запускати задачі через .delay().
4. Побачили магію: код виконується в іншому вікні терміналу!
Тепер ви вмієте: Розвантажувати свій додаток від важкої роботи.
🤔 Тизер наступного уроку: Але чекайте... А як дізнатися результат виконання задачі у коді? Як сказати користувачу "Твій PDF готовий", якщо ми відправили задачу у фоні? На наступному уроці розберемо Celery Backend і те, як зберігати результати.
Це був CS50... тобто, наш урок. Побачимось! 🖐️🎤