← Усі статті

Чому BullMQ замість конвертації файлів прямо в API

Конвертація в HTTP-запиті vs черга на Redis: p95 впав з 800 мс до 3,8 мс, пропускна здатність зросла в 4,8 раза — і ціна складності.

Зміст

Коротко

Застосунок для конвертації й шарингу файлів спочатку робив всю роботу всередині HTTP-запиту. Зі зростанням розмірів файлів користувачі чекали сотні мілісекунд там, де відповідь могла прийти одразу. Автор виніс важку обробку в BullMQ і Redis — і отримав вимірюваний виграш за затримкою й пропускною здатністю.

Що сталося

Перша версія була простою: завантаження → конвертація в тому ж процесі, що обробляє API → відповідь із результатом. На маленьких файлах це працювало. Коли обсяги зросли, з'єднання трималося відкритим, поки сервер зайнятий CPU й диском — хоча клієнту в цей момент потрібен був лише факт «прийнято в роботу».

Новий потік: завантаження → задача в BullMQ → миттєва відповідь API → воркер конвертує → оновлення статусу → користувач отримує файл. Redis зберігає чергу; воркери масштабуються за паралелізмом; повтори й обробка збоїв вбудовані в модель черги.

Автор прогнав навантажувальний тест із 20 паралельними запитами. p95 затримки API впав приблизно в 212 разів (з 800 мс до 3,8 мс). Пропускна здатність зросла в 4,8 раза (з 1,3 до 6,2 запитів на секунду). Прискорилася не сама конвертація — змінилася архітектура: важка робота пішла з критичного шляху запиту.

Чому це важливо

Синхронна обробка в API здається простішою, поки навантаження низьке. Але будь-який довгий I/O або CPU в обробнику запиту б'є по таймаутах, пулі з'єднань і UX. Патерн «прийняти швидко, обробити окремо» — базовий для файлів, відео, звітів, розсилок.

Ціна асинхронності чесна: потрібні Redis, процеси-воркери, моніторинг черги й відкладена узгодженість — користувач не отримує файл у тій самій відповіді, що завантаження. Якщо бізнес вимагає миттєвого результату в одному HTTP-циклі, синхронний шлях може лишитися виправданим. Для конвертації й шарингу це рідко так.

На практиці

  1. Відокремте прийом файлу від важкої обробки — API повертає jobId і статус.
  2. Оберіть чергу з повторами й чергою «мертвих» задач (BullMQ на Redis — поширений варіант у Node.js).
  3. Масштабуйте воркери, а не лише репліки API — задачі, що навантажують CPU, живуть там.
  4. Віддавайте клієнту опитування статусу, webhook або SSE для стану «готово».
  5. Заміряйте p95/p99 API окремо від часу повної обробки задачі.
  6. Задокументуйте компроміс: простіший код vs інфраструктура й затримка до результату.

Підсумок

Історія на Dev.to — коротке, але цифрами підкріплене нагадування: часто виграш дає не «прискорення функції», а винесення роботи з HTTP-запиту. BullMQ + Redis окупилися для файлового сервісу; ваш поріг може бути іншим, але принцип універсальний.