Модуль 34

Background jobs та черги задач з Redis

Ось готовий урок, створений спеціально за твоїм запитом у стилі David Malan (CS50).


🎓 Урок: Background Jobs та черги задач з Redis

Привіт, друзі! Радий бачити вас на цій лекції. 👋

Сьогодні ми не просто пишемо код. Ми сьогодні будемо рятувати наших користувачів від нудьги та роздратування. Ми поговоримо про магію, яка відбувається "за лаштунками", коли ви натискаєте кнопку "Купити", "Обробити відео" або "Згенерувати звіт".

Тема звучить як "Background jobs та черги задач з Redis". Звучить складно? Можливо. Але до кінця цього уроку ви будете думати про це так само просто, як про замовлення кави.

Поїхали! 🚀


1. 🔥 Вступ: Чому ваш сайт "гальмує"?

Уявіть ситуацію. Ви заходите на сайт, реєструєтесь, вводите свій емейл і тиснете "Зареєструватися". І тут...

⏳ Коліщатко крутиться... ⏳ Крутиться... ⏳ Ще крутиться... ⏳ Пройшло 5 секунд... ✅ Нарешті: "Успішно! Лист відправлено".

Питання до вас: Ви будете чекати ці 5 секунд наступного разу? Або ви просто закриєте вкладку, подумавши, що сайт зламався? Більшість людей піде.

У чому проблема? Коли ваш веб-сервер (код, який ви написали) відправляє емейл, він робить це синхронно. Тобто він каже браузеру користувача: "Зачекай, не йди, я зараз дзвоню поштовому сервісу... вони не беруть слухавку... ага, взяли... передаю дані... все, відправив! Тепер можеш показати сторінку успіху".

Це жахливий UX (User Experience). Користувач не повинен чекати, поки ваш сервер робить важку роботу.

Аналогія з кав'ярнею ☕️ Уявіть Starbucks. Ви підходите до каси (це веб-сервер) і замовляєте лате. Касир приймає замовлення і... сам йде робити каву. Він меле зерна, збиває молоко, малює сердечко. Весь цей час черга за вами стоїть і чекає. Каса заблокована. Це — синхронний підхід.

Як це працює в реальному житті? Касир бере гроші, пише ваше ім'я на стаканчику, ставить стаканчик у чергу на стійку і кричить: "Наступний!". А спеціальна людина (бариста) бере стаканчик і робить каву. Це — асинхронний підхід (Background job).

Ось про це ми сьогодні й поговоримо.


2. 🧠 Теоретична база (Як це працює під капотом)

Щоб реалізувати "схему Starbucks" у коді, нам потрібні три компоненти:

  1. Producer (Виробник/Веб-сервер) — той, хто приймає запит від користувача (Касир).
  2. Broker (Черга/Redis) — місце, де лежать задачі, які треба виконати (Стійка зі стаканчиками).
  3. Consumer / Worker (Робітник) — окремий процес, який виконує задачі (Бариста).

Чому Redis?

Redis — це супершвидка база даних, яка працює в оперативній пам'яті. Вона ідеально підходить на роль Брокера. Уявіть Redis як дошку оголошень.

Як це працює (Логіка):

  1. Користувач тисне "Зареєструватися".
  2. Веб-сервер зберігає користувача в базу даних.
  3. Веб-сервер каже: "Окей, треба відправити лист, але я не буду це робити зараз".
  4. Веб-сервер формує маленьку записку (JSON): { "task": "send_email", "user_id": 42 }.
  5. Він кидає цю записку в Redis (у список, чергу). Це займає мілісекунди.
  6. Веб-сервер миттєво відповідає користувачеві: "Все готово, перевір пошту!".

Тим часом, десь в іншому місці працює Worker. 1. Worker постійно дивиться на Redis: "Є щось нове?" 2. Бачить записку { "task": "send_email", "user_id": 42 }. 3. Забирає її. 4. Відправляє реальний емейл (це може тривати хоч 10 секунд). 5. Позначає задачу як виконану.

❗️ Що треба запам’ятати: * Основний потік (Web) має бути швидким. Не блокуйте його. * Redis тут виступає як буфер. Він зберігає задачі, щоб вони не загубилися. * Worker — це окрема програма, яка працює паралельно з вашим сайтом.


3. 🧪 Приклади (Код і реальність)

Давайте подивимось на це очима програміста. Я буду використовувати псевдокод (схожий на Python/JS), щоб ми фокусувалися на суті, а не на дужках.

Приклад 1: Поганий код (Синхронний) ❌

def register_user(request):
    user = save_to_db(request.data)

    # ТУТ ПРОБЛЕМА! 
    # Сервер зависає тут, поки лист не піде
    email_service.send(user.email, "Вітаємо!") 

    return "Успішно!"

Що очікуємо? Користувач чекає відповіді стільки, скільки працює email_service.

Приклад 2: Хороший код (Асинхронний з Redis) ✅

Тут ми використовуємо чергу (наприклад, бібліотеку, яка працює з Redis).

Веб-сервер (Касир):

def register_user(request):
    user = save_to_db(request.data)

    # Ми просто додаємо задачу в Redis. Це миттєво.
    queue.enqueue('send_welcome_email', user_id=user.id)

    return "Успішно! (Ми вже працюємо над вашим листом)"

Worker (Бариста): Це окремий процес, який працює вічно

while True:
    # Чекаємо задачу з Redis
    task = redis.pop_task() 

    if task.name == 'send_welcome_email':
        user = get_user(task.user_id)
        # Важка робота виконується тут
        email_service.send(user.email, "Вітаємо!")

Чому це круто? Навіть якщо відправка листа впаде з помилкою, користувач вже отримав сторінку "Успішно". А воркер може спробувати відправити лист ще раз пізніше.

Приклад 3: Реальний кейс (Генерація звіту) 📊

Уявіть, що ви адміністратор інтернет-магазину і хочете завантажити PDF-звіт продажів за рік. Це складний розрахунок.

  1. Ви тиснете "Завантажити звіт".
  2. Сайт каже: "Звіт формується. Ми надішлемо вам сповіщення, коли він буде готовий".
  3. Worker у фоні рахує цифри 5 хвилин, генерує PDF, заливає його на S3 (хмарне сховище).
  4. Worker відправляє вам пуш-повідомлення або лист з посиланням.

Якби ми робили це без черг, ваш браузер відвалився б по тайм-ауту через 30 секунд.


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

Тепер ваша черга думати! Уявіть, що ви архітектор системи.

Завдання 1: "Детектив" 🕵️‍♂️ Подивіться на цей список дій на веб-сайті. Які з них треба винести у Background Job (у воркер)? 1. Перевірка пароля при вході. 2. Зміна розміру завантаженої аватарки (resize). 3. Показ ціни товару. 4. Щоденне нарахування бонусів усім користувачам о 00:00.

(Подумайте 5 секунд...) Відповідь: 2 та 4. (1 і 3 потрібні користувачеві негайно, тут не можна чекати).

Завдання 2: "Аварія на кухні" 🔥 Ви використовуєте чергу для відправки SMS. Раптом сервіс SMS-розсилки "ліг" на 1 годину. Що станеться з вашою чергою в Redis? * А) Задачі зникнуть. * Б) Задачі накопичаться в Redis і виконаються, коли сервіс підніметься. * В) Сайт перестане працювати.

(Ваша відповідь?) Правильно — Б. Redis буде збирати задачі. Як тільки сервіс запрацює, воркери розгребуть цю купу. Сайт при цьому працює ідеально!

Завдання 3: Міні-кейс Ви розробляєте Instagram. Користувач завантажує відео. Опишіть (словами), що робить сервер, а що робить воркер. Підказка: Відео треба перекодувати в різні якості (360p, 720p, 1080p).


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

Як відрізнити новачка від профі в цій темі?

1. Передача даних (Payload) * 🛑 Новачок: Кладе в Redis весь об'єкт користувача (ім'я, емейл, хеш пароля, адресу...). * Чому погано: Поки задача дійде до воркера, користувач міг змінити емейл у базі. Воркер відправить лист на старий емейл. * ✅ Профі: Кладе в Redis тільки ID (user_id). * Чому добре: Воркер отримає ID, піде в базу і візьме найсвіжіші дані. "Single Source of Truth".

2. Ідемпотентність (Idempotency) Страшне слово, проста суть. Що, якщо Redis глюкне і видасть одну й ту ж задачу воркеру двічі? * Чи спишемо ми гроші з клієнта двічі? 😱 * Досвідчений розробник пише код так, щоб повторне виконання задачі не ламало систему (наприклад, перевіряє статус "Вже оплачено" перед списанням).

3. Моніторинг Черги — це "темна матерія". Ви не бачите, що там, поки не подивитесь. Профі завжди ставлять дашборд (наприклад, для Redis це часто роблять бібліотеки типу Sidekiq або Bull Board), щоб бачити: "Ого, у нас 10 000 невідправлених листів, треба запускати більше воркерів!".


6. 🧩 Підсумок

Ну що, підіб’ємо підсумки?

  1. Синхронно = чекати на лінії. Асинхронно = відправити повідомлення.
  2. Важкі задачі (емейли, обробка файлів, звіти) виносимо у фон.
  3. Redis — це наша черга (буфер).
  4. Worker — це трудяга, який розгрібає чергу.

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

👇 Тизер наступного уроку: Окей, ми навчилися виконувати задачі десь там. Але що, якщо нам треба виконати задачу рівно о 9:00 щоп'ятниці? Чи може Redis бути будильником? На наступному уроці поговоримо про Cron Jobs та планувальники задач.

А поки — спробуйте не бути синхронними у своєму житті. Делегуйте! 😉 До зустрічі!