Назад в блог
Заказное ПО

Что такое очередь сообщений? Фоновые задачи с RabbitMQ

Что такое очередь сообщений и зачем она нужна? Производители и потребители, вынос отправки писем, счетов и уведомлений в фон с RabbitMQ, подтверждения, повторные попытки, очередь недоставленных сообщений, идемпотентность и случаи, когда очередь не нужна.

Mesaj KuyruğuRabbitMQBackendMimari

Очередь сообщений (message queue) это промежуточный слой, куда приложение кладёт задачу в виде сообщения вместо того, чтобы выполнять её сразу, а другой процесс по порядку забирает эти сообщения и обрабатывает. Коротко: она отделяет от веб-запроса работу, которая не должна заставлять пользователя ждать или зависит от внешней системы (письма, выставление счетов, уведомления, отчёты); если внешняя система тормозит или падает, задача не теряется, а ждёт в очереди. RabbitMQ один из самых распространённых инструментов с открытым кодом для этого.

Что такое очередь сообщений и как она работает?

В модели три части. Производитель (producer) отправляет небольшое сообщение с описанием работы, например «выставить счёт по заказу 42». Брокер, здесь RabbitMQ, надёжно сохраняет сообщение. Потребитель (consumer) это отдельный рабочий процесс: он берёт сообщение, выполняет работу и подтверждает (ack) завершение. Если процесс упал до подтверждения, брокер отдаёт сообщение другому обработчику. Благодаря этому веб-сервер сохраняет заказ и сразу отвечает пользователю, а счёт создаётся через несколько секунд в фоне.

Для чего используется очередь сообщений?

  • Отправка писем и SMS: экраны регистрации и оформления заказа не ждут, даже если провайдер медленный.
  • Счета и государственные интеграции: для внешних сервисов с задержкой ответа, например интеграции электронных счетов, повторы берёт на себя очередь.
  • Входящие события вебхуков: событие сразу принимается и ставится в очередь, обработка идёт отдельно; подробнее в статье что такое вебхук.
  • Тяжёлые задачи: генерация PDF и отчётов, обработка изображений, массовый импорт.
  • Связь между сервисами: когда на событие в одном сервисе должны реагировать несколько других.
Очередь гарантирует, что работа не потеряется, но не гарантирует, что она выполнится один раз. Одно и то же сообщение может прийти повторно, поэтому каждый потребитель должен быть идемпотентным: повторное получение той же задачи не должно менять результат.

Подтверждение, повторы и очередь недоставленных сообщений

В надёжной настройке три решения принимаются заранее. Первое: подтверждение. Потребитель подтверждает сообщение после реального завершения работы, а не при получении. Второе: повторы. При временных ошибках сообщение повторяется ограниченное число раз с задержкой, без бесконечного цикла. Третье: очередь недоставленных сообщений (dead letter queue). Сообщение, исчерпавшее попытки, попадает в отдельную очередь, где его отслеживают и после устранения причины отправляют заново вручную. Количество накопившихся там сообщений нужно мониторить и поднимать тревогу при превышении порога.

Пример на Node.js ниже показывает производителя, который после заказа ставит счёт в очередь, и потребителя, который его обрабатывает. Идентификатор сообщения это номер заказа; функция createInvoiceOnce в потребителе никогда не создаёт второй счёт для того же заказа.

import amqp from 'amqplib';

const conn = await amqp.connect(process.env.AMQP_URL ?? 'amqp://localhost');
const ch = await conn.createChannel();
await ch.assertQueue('invoices', { durable: true });

// Producer: the web request only drops a message and returns.
export function enqueueInvoice(orderId: string) {
  ch.sendToQueue('invoices', Buffer.from(JSON.stringify({ orderId })), {
    persistent: true,
    messageId: orderId, // used for idempotency on the consumer side
  });
}

// Consumer: a separate worker process.
await ch.prefetch(5);
await ch.consume('invoices', async (msg) => {
  if (!msg) return;
  const { orderId } = JSON.parse(msg.content.toString());
  try {
    await createInvoiceOnce(orderId); // safe to run twice for the same order
    ch.ack(msg);
  } catch {
    ch.nack(msg, false, false); // goes to the dead letter queue
  }
});

RabbitMQ, Redis или Kafka?

RabbitMQ создан для классических очередей задач: маршрутизация, подтверждения, приоритеты и очереди недоставленных сообщений есть из коробки. Если в приложении уже есть Redis, для фоновых задач с небольшим объёмом могут подойти библиотеки очередей на Redis; о других применениях читайте статью что такое Redis. Kafka это журнал событий, который долго хранит сообщения; он оправдан для больших потоков событий и когда данные нужно перечитывать позже, а для простой очереди задач избыточен. Выбор определяют срок хранения сообщений и число читателей, а не популярность инструмента.

Когда очередь сообщений не нужна?

Не каждой фоновой задаче нужна очередь. Для отчётов или очистки по расписанию проще плановая задача (cron job). В приложении с небольшим трафиком на одном сервере часто хватает таблицы «ожидающие задачи» в базе данных и небольшого обработчика, который её читает. Очередь это ещё один компонент, который нужно мониторить, резервировать и обновлять. По той же причине стоит ответить на вопрос микросервисы или монолит, прежде чем делить приложение на сервисы.

Итог

Очередь сообщений надёжно выносит в фон работу, которая не должна заставлять пользователя ждать или зависит от внешних систем. Её ценность проявляется, когда подтверждения, ограниченные повторы, очередь недоставленных сообщений и идемпотентные потребители настроены вместе. Если хотите вместе спланировать фоновую обработку в вашем проекте, загляните на страницу заказное ПО или напишите нам через форму запросить смету.

Let's Build Your Project

Get a free consultation for your website, mobile app, or corporate software project.

Get a Free QuoteExplore our Custom Software service