Ось готовий урок, створений спеціально за твоїм запитом, у стилі енергійних та наочних лекцій CS50.
🎓 Урок: Що таке Celery і навіщо нам фонові задачі?
Привіт, друзі! Радий бачити вас на цьому занятті.
Сьогодні ми поговоримо про одну з найважливіших концепцій у веб-розробці, яка відрізняє "просто працюючий" сайт від сайту, що працює швидко та надійно. Ми поговоримо про Celery та фонові задачі.
Готові? Поїхали! 🚀
1. 🔥 Вступ: Проблема черги за кавою
Уявіть, що ви зайшли в популярну кав'ярню в центрі міста. Ви підходите до каси, замовляєте складний лате з кокосовим молоком і сиропом.
А тепер уявіть сценарій А: Касир приймає ваше замовлення, бере горнятко, йде до кавомашини, 2 хвилини збиває молоко, варить еспресо, малює сердечко пінкою, віддає вам каву і тільки після цього повертається до каси, щоб прийняти замовлення наступної людини в черзі.
❓ Питання до вас: Що станеться з чергою, якщо касир працюватиме так із кожним клієнтом? Правильно. Черга вийде на вулицю. Люди будуть лютувати. Система "зависне".
Але в реальному житті (Сценарій Б) все інакше: Касир приймає замовлення, бере гроші й кричить баристі: "Один лате!". Ви відходите вбік, касир одразу обслуговує наступного. Бариста (інша людина!) готує каву у фоновому режимі.
У веб-розробці: * Касир — це ваш веб-сервер (Django, Flask, FastAPI). Його робота — швидко прийняти запит і сказати "Ок, прийнято!". * Приготування кави — це важка задача (відправка 1000 емейлів, обробка відео, генерація PDF-звіту). * Бариста — це Celery.
Без Celery ваш сайт — це той повільний касир. Поки він відправляє емейл підтвердження реєстрації (це може тривати 2-3 секунди), користувач дивиться на іконку завантаження і думає, що сайт зламався.
Чому без цього не обійтись? Тому що користувачі не люблять чекати. Більше 3 секунд очікування — і клієнт йде. Celery дозволяє робити важку роботу "за лаштунками", поки користувач продовжує серфити сторінками.
2. 🧠 Теоретична база (Як це працює під капотом)
Давайте розберемо механіку. Celery — це не магія, це система черг задач.
У нас є три головні дійові особи. Уявіть собі кухню ресторану:
- Producer (Продюсер/Клієнт): Це ваш основний код (наприклад, Django view). Коли треба зробити щось важке, він не робить це сам. Він створює Задачу (Task) і кладе її в спеціальне місце.
- Broker (Брокер/Посередник): Це "дошка замовлень" або "поштова скринька". Найчастіше це Redis або RabbitMQ. Продюсер кидає туди задачу ("Треба відправити лист"), і вона там лежить, поки хтось її не забере.
- Worker (Робітник/Споживач): Це і є Celery. Це окремий процес (програма), який постійно моніторить Брокера. Як тільки там з'являється задача, Воркер хапає її і починає виконувати.
Що треба запам'ятати (обов'язково):
- Ваш сайт (Django/Flask) і Celery — це два різні процеси. Якщо ви зупините сайт, Celery може працювати далі. Якщо впаде Celery, сайт працюватиме, але листи не будуть відправлятися.
- Вони спілкуються через Брокера (посередника). Без Брокера вони не чують одне одного.
Інтуїтивне розуміння:
Ви (сайт) пишете записку "Помий посуд" і кидаєте в коробку (Redis). Ваш брат (Celery) періодично заглядає в коробку, дістає записку і йде мити посуд. Ви в цей час можете дивитися телевізор.
3. 🧪 Приклади (від простого до реального)
Приклад 1: "Важка" математика
Припустимо, у нас є функція, яка довго думає (імітуємо це через sleep).
Звичайний (синхронний) код:
import time
def add(x, y):
time.sleep(5) # Імітуємо 5 секунд важкої роботи
return x + y
# Якщо ви викличете це у Django view, користувач чекатиме 5 секунд!
result = add(4, 4)
print("Готово!")
❓ Що ви очікуєте побачити? Програма "замерзне" на 5 секунд, і тільки потім напише "Готово!".
А тепер з Celery:
from celery import shared_task
import time
@shared_task # Цей декоратор перетворює функцію на задачу Celery
def add(x, y):
time.sleep(5)
return x + y
# Виклик:
# Ми використовуємо .delay(), щоб відправити задачу брокеру
result = add.delay(4, 4)
print("Я не чекав! Я пішов далі!")
Пояснення: Метод .delay(4, 4) не виконує функцію. Він миттєво відправляє повідомлення в Redis: "Гей, хтось вільний, порахуйте 4+4!". І програма йде далі миттєво. Десь там, у фоні, Celery прокинеться і порахує це.
Приклад 2: Реальний кейс (Email)
Типова задача: Користувач реєструється, треба відправити "Welcome Email".
# tasks.py
from celery import shared_task
from django.core.mail import send_mail
@shared_task
def send_welcome_email(user_email):
# Це може зайняти 2-5 секунд, залежно від SMTP сервера
send_mail(
'Ласкаво просимо!',
'Ми раді вас бачити...',
'admin@mysite.com',
[user_email],
)
return "Email sent"
# views.py (де відбувається реєстрація)
def register_user(request):
user = User.objects.create(...) # Створили користувача
# Віддаємо задачу Celery!
send_welcome_email.delay(user.email)
# Миттєво повертаємо відповідь
return HttpResponse("Реєстрація успішна! Перевірте пошту.")
Чому це круто? Користувач натиснув "Зареєструватися" і миттєво побачив сторінку успіху. Лист прийде через 3 секунди, але користувачу вже байдуже, він не чекав.
4. 🛠 Практична частина
Завдання для закріплення. Спробуйте уявити або написати псевдокод для цих ситуацій.
-
🔹 Завдання "Hello World": Напишіть задачу Celery, яка приймає ім'я користувача і просто друкує в консоль воркера:
f"Привіт, {name}! Я працюю у фоні.". Як ви її викличете з основного коду? -
🔹 Зміна умов: У вас є інтернет-магазин. Після покупки треба: 1) Списати товар зі складу (швидко), 2) Згенерувати PDF-чек (довго), 3) Відправити чек на пошту (середньо). Питання: Які з цих дій ви залишите у view (синхронно), а які віддасте Celery?
-
🔹 Виправлення помилки: Студент написав код:
resize_image(image_path)(без.delay). Сайт працює, але коли завантажуєш велике фото — сторінка вантажиться 10 секунд. Що треба додати до виклику функції? -
🔹 Міні-кейс "Нічний звіт": Вашому босу треба отримувати звіт про продажі щодня о 9:00 ранку. Генерація звіту займає 10 хвилин. Чи може Celery допомогти тут? (Підказка: гугліть Celery Beat).
-
🔹 А що, якщо... Ви відправили задачу в Celery (
add.delay(2, 2)), але забули запустити сам процес Celery Worker у терміналі. Що станеться із задачею? Вона зникне чи чекатиме?
5. 💡 Мислення як у розробника
Ось тут я хочу, щоб ви думали як сеньйори, а не як джуніори.
⚠️ Типова помилка новачка: Передача об'єктів бази даних
Погано:
# Не робіть так!
user = User.objects.get(id=1)
send_email.delay(user) # Передаємо цілий об'єкт Django ORM
Чому? Поки задача дійде до воркера (через 10 мс або через годину), дані користувача в базі могли змінитися! Або об'єкт може не коректно "серіалізуватися" (перетворитися в текст для передачі через Redis).
Як думає профі: "Я передам тільки ID. А Celery сам дістане свіжі дані з бази". Добре:
send_email.delay(user.id) # Передаємо тільки ID (int)
⚠️ Помилка: "Celery — це магія швидкості"
Celery не робить ваш код швидшим. Він просто робить його асинхронним (відкладеним). Якщо генерація звіту займає 10 хвилин, вона і в Celery займе 10 хвилин. Але вона не блокуватиме основний сайт.
💡 Порада з практики:
Завжди майте на увазі, що задача може виконатися двічі (через збій мережі абощо). Пишіть код так, щоб повторне виконання нічого не ламало (це називається Ідемпотентність). Наприклад, перед відправкою листа перевірте, чи не був він уже відправлений.
6. 🧩 Підсумок
Отже, що ми сьогодні зрозуміли:
- Веб-запити мають бути блискавичними.
- Все, що займає час (пошта, звіти, обробка файлів), ми віддаємо Celery.
- Celery, Брокер (Redis) і ваш Сайт — це команда, де кожен робить свою справу.
- Ми передаємо в задачі прості дані (ID), а не складні об'єкти.
Що ви тепер вмієте? Ви розумієте архітектуру фонових задач. Ви більше не змусите користувача чекати, поки ваш код "думає". Ви знаєте, як розвантажити сервер.
🔜 У наступній серії: Ми навчилися запускати задачі вручну. Але що, якщо ми хочемо, щоб код запускався сам? Скажімо, кожного понеділка о 8:00? Ми поговоримо про Celery Beat і періодичні задачі.
Це був CS50... тобто, урок про Celery. До зустрічі! 👋