Очереди задач в JavaScript (Node.js): полное руководство для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем нужны очереди задач в JavaScript?

В современной веб-разработке приложения часто сталкиваются с задачами, которые не могут быть выполнены мгновенно в рамках одного HTTP-запроса. Отправка электронных писем, обработка изображений, генерация PDF-отчетов или синхронизация с внешними API — все это требует времени и может "завесить" сервер, если выполнять их синхронно.

Очереди задач (Task Queues) решают эту проблему. Они позволяют отложить выполнение ресурсоемких операций и обрабатывать их асинхронно в фоновом режиме. В этой статье мы разберем, как создавать и управлять очередями задач в среде Node.js, используя популярные библиотеки.

1. Основы работы с очередями в Node.js

Очередь задач — это структура данных, работающая по принципу FIFO (First In, First Out). Задачи добавляются в конец очереди, а обрабатываются из начала. В контексте Node.js это означает, что ваш сервер может быстро ответить пользователю ("Задача принята в обработку"), а сама задача будет выполнена позже.

Для работы с очередями в Node.js используются специализированные библиотеки, которые полагаются на внешние хранилища (чаще всего Redis). Рассмотрим две самые популярные:

  • Bull — современная, быстрая и стабильная библиотека на основе Redis.
  • Kue — более старая, но всё ещё популярная библиотека с встроенным веб-интерфейсом.

Мы сосредоточимся на Bull, так как она является стандартом де-факто для новых проектов.

1.1 Установка и подключение Bull

Для начала установите необходимые зависимости:

npm install bull ioredis

Теперь создадим простую очередь:

const Queue = require('bull');
const myQueue = new Queue('emailQueue', {
  redis: {
    host: '127.0.0.1',
    port: 6379
  }
});

// Добавляем задачу в очередь
myQueue.add({
  to: 'user@example.com',
  subject: 'Приветственное письмо',
  body: 'Добро пожаловать на наш сайт!'
});

console.log('Задача добавлена в очередь');

В этом примере мы создали очередь с именем emailQueue и добавили в нее одну задачу — отправку письма. Задача пока не выполнена, она просто ждет своего обработчика.

2. Обработка задач из очереди

Чтобы задачи начали выполняться, нам нужен обработчик (consumer). Он будет "слушать" очередь и брать из нее задачи для выполнения.

Создадим файл worker.js:

const Queue = require('bull');
const emailQueue = new Queue('emailQueue', {
  redis: { host: '127.0.0.1', port: 6379 }
});

// Функция-обработчик
emailQueue.process(async (job) => {
  const { to, subject, body } = job.data;
  console.log(`Отправка письма на ${to}...`);
  
  // Имитация отправки письма (в реальном проекте тут был бы nodemailer)
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  console.log(`Письмо "${subject}" отправлено на ${to}`);
  return { status: 'sent', email: to };
});

console.log('Обработчик запущен и ожидает задачи...');

Запустите этот скрипт, а затем добавьте задачу из первого примера. Вы увидите, как задача будет обработана.

2.1 Обработка ошибок и повторные попытки

В реальных проектах задачи могут завершаться ошибкой (например, SMTP-сервер недоступен). Bull предоставляет встроенный механизм повторных попыток:

emailQueue.add(
  { to: 'user@example.com', subject: 'Важное письмо' },
  { 
    attempts: 5,          // Количество попыток
    backoff: { type: 'exponential', delay: 2000 } // Экспоненциальная задержка
  }
);

// В обработчике можно обработать неудачу
emailQueue.on('failed', (job, err) => {
  console.error(`Задача ${job.id} провалилась: ${err.message}`);
});

3. Расширенные возможности очередей

Bull предоставляет множество полезных функций для управления задачами.

3.1 Приоритеты задач

Вы можете задать приоритет (чем меньше число, тем выше приоритет):

// Высокий приоритет
myQueue.add({ type: 'critical' }, { priority: 1 });

// Низкий приоритет
myQueue.add({ type: 'bulk' }, { priority: 10 });

3.2 Задержка выполнения

Отложите выполнение задачи на определенное время:

// Отправить письмо через 1 час
myQueue.add(
  { to: 'user@example.com', subject: 'Напоминание' },
  { delay: 60 * 60 * 1000 } // 3600000 мс = 1 час
);

3.3 Повторяющиеся задачи (cron)

Настройте задачи, которые выполняются по расписанию:

const Queue = require('bull');
const reportQueue = new Queue('reportQueue');

// Генерация отчета каждый день в 9:00
reportQueue.add(
  { type: 'daily_report' },
  { repeat: { cron: '0 9 * * *' } }
);

reportQueue.process(async (job) => {
  console.log('Генерирую ежедневный отчет...');
  // ... логика генерации
});

4. Практический пример: система обработки заказов

Соберем всё вместе и создадим простую систему для обработки заказов в интернет-магазине.

Структура проекта:

  • orderQueue.js — создание очереди и добавление заказов
  • orderWorker.js — обработчик, который выполняет несколько шагов

orderQueue.js:

const Queue = require('bull');

const orderQueue = new Queue('orderProcessing', {
  redis: { host: '127.0.0.1', port: 6379 }
});

// Добавляем новый заказ
async function addOrder(orderData) {
  const job = await orderQueue.add(orderData, {
    attempts: 3,
    backoff: { type: 'fixed', delay: 5000 }
  });
  console.log(`Заказ #${job.id} добавлен в очередь`);
  return job.id;
}

// Пример добавления
addOrder({
  orderId: 12345,
  userId: 42,
  items: ['Ноутбук', 'Мышь'],
  total: 1500
});

orderWorker.js:

const Queue =                

Блоги

Рекомендаций по книгам