Асинхронная очередь избавляет веб-запрос от ожидания завершения ресурсоёмких задач, но сама по себе не решает проблему конкуренции между задачами. Проблема возникает, когда импорт, повторная обработка или кампания создаёт тысячи сообщений и занимает всех потребителей. Действие с немедленным эффектом — подтверждение заказа, резервирование запасов, блокировка учётной записи или отправка транзакционного уведомления — оказывается позади работы, которая может подождать.
Управление приоритетами в PHP-очередях заключается не только в добавлении числового поля в сообщение. Это архитектурное решение, которое должно отражать бизнес-поток, защищать ограниченные зависимости и сохранять предсказуемое поведение при росте нагрузки.
Классифицируйте работу по влиянию, сроку и стоимости

Прежде чем создавать очереди, составьте перечень асинхронных задач. Для каждой определите, кто её запускает, какую зависимость она использует, сколько обычно длится, какой у неё бизнес-срок и что произойдёт при задержке. Срочность не обязательно равна важности: финансовая сверка может быть очень важной, но допускать ожидание в несколько часов; валидация платежа может требовать быстрого ответа, хотя её выполнение кратковременно.
Полезная классификация обычно включает четыре класса обслуживания:
- Критический: действия, защищающие деньги, безопасность, согласованность или немедленные обязательства. Для них должно быть предусмотрено очень низкое целевое время ожидания и зарезервированная мощность.
- Интерактивный: работа, инициированная человеком или необходимая для завершения опыта, близкого к реальному времени, например создание документа, запрошенного из приложения.
- Отложенный: необходимые задачи без немедленного срока, например периодические синхронизации, сводки или обновления индексов.
- Массовый: импорты, миграции, переиндексации, кампании и повторные обработки. Их объём или стоимость требуют ограничения темпа, даже когда другой нагрузки нет.
Также фиксируйте стоимость каждой задачи. Сообщение, вызывающее API с ограниченной квотой, выполняющее ресурсоёмкий запрос или обрабатывающее большой файл, не должно конкурировать так же, как краткое локальное обновление. Класс обслуживания должен выражать срок и тип давления, которое задача создаёт для системы.
Разделяйте очереди, когда нужна реальная изоляция
Единая очередь с приоритетами может подойти, если задачи выполняются однородно, используют одни и те же зависимости, а транспорт обеспечивает надёжный приоритет. Однако порядок извлечения сам по себе не гарантирует наличия мощности: массовая задача, которая уже выполняется, продолжит занимать рабочий процесс, соединение или внешнюю квоту.
Разделяйте очереди при наличии хотя бы одного из следующих ограничений:
- У критических и массовых задач явно различаются целевые показатели ожидания.
- Один тип задач обращается к хрупкой зависимости или зависимости с ограничением частоты запросов, например к API платежей, почты или ERP.
- Длительность сильно различается, и долгие задачи удерживают процессы слишком долго.
- Требуется независимое управление развёртыванием, приостановкой, повторными попытками или масштабированием.
- Ошибка или аномальные входные данные в одном потоке не должны ухудшать работу другого потока.
В PHP-приложении наиболее понятный паттерн — маршрутизировать сообщения в явные очереди, например critical, interactive, deferred и bulk. Компонентом обмена сообщениями может быть Symfony Messenger, Laravel Queues или собственная интеграция с выбранным брокером сообщений; принцип не зависит от фреймворка. Приоритет внутри очереди может дополнять это разделение для упорядочивания похожих задач, но не заменять изоляцию между несовместимыми классами.
Определите зарезервированную мощность и максимальную параллельность
Назначьте потребителей для каждого класса и установите как операционные минимумы, так и максимумы. Критической очереди нужна мощность, которую не смогут поглотить импорты. Массовая же очередь должна иметь максимум параллельности, чтобы не перегружать базу данных, CPU, хранилище или внешних провайдеров.
Не настраивайте все рабочие процессы на чтение из всех очередей с абсолютным предпочтением критической. Такой подход может оставить мощности неиспользуемыми, если зарезервированные потребители не могут брать другие задачи, или вызвать голодание, если могут делать это без правил. Практичная альтернатива — сочетать:
- Выделенные рабочие процессы для критических и интерактивных задач.
- Общие рабочие процессы, обслуживающие отложенные и массовые задачи согласно квотам.
- Лимиты по типу зависимости, а не только по общему числу процессов.
- Масштабирование на основе глубины очереди и возраста сообщений, а не исключительно загрузки CPU.
Правильное число не универсально. Оно должно определяться параллельностью, которую выдерживают база данных и API, наблюдаемой длительностью и целевым временем ожидания каждого класса.
Предотвращайте голодание и применяйте обратное давление
Отдавать предпочтение срочному не означает, что отложенная работа никогда не должна завершаться. Если критические сообщения есть всегда, политика строгого приоритета может вызвать голодание: задачи более низкого уровня будут стареть бесконечно. Установите измеримое правило справедливости, например обрабатывать квоту отложенных сообщений после ограниченного числа критических либо резервировать небольшую долю мощности для несрочной работы.
Правило должно учитывать ограничения зависимостей. Если критические и массовые задачи записывают в одну и ту же таблицу с дорогостоящими блокировками, их параллельное выполнение может ухудшить задержку. В таком случае квоту следует применять к общему ресурсу либо стоит переработать задачу в более мелкие пакеты.
Обратное давление возникает, когда поступает больше работы, чем может быть завершено. Оно не устраняется бесконечным увеличением числа рабочих процессов. Определите реакцию:
- Ограничивайте размер, частоту или параллельность импортов в источнике.
- Разделяйте пакеты на возобновляемые единицы и контролируйте, сколько из них публикуется одновременно.
- Откладывайте отложенную работу с явным расписанием, когда очередь или зависимость превышает порог.
- Учитывайте ответы об ограничении частоты запросов с паузами и отложенными повторными попытками вместо немедленных повторов.
- Информируйте в продукте, когда операция принята в обработку и когда она действительно завершена.
Важно различать принятие и выполнение: сообщение о том, что импорт получен, не означает, что он может начаться немедленно. Такая прозрачность предотвращает интерпретацию технического изменения как обещания мгновенной доступности.
Контролируйте повторные попытки, медленную работу и идемпотентность
Повторные попытки потребляют мощность и могут случайно стать приоритетной нагрузкой. Классифицируйте ошибки как временные и постоянные. Временный сетевой сбой может оправдывать повторную попытку с увеличивающимся ожиданием и временным разбросом; невалидная проверка, несуществующий ресурс или отозванные учётные данные должны направляться в контур проверки, а не бесконечно повторяться.
Установите максимальное время выполнения для каждого типа задач. Медленная задача не должна удерживать рабочий процесс бесконечно. Если её можно разделить, обрабатывайте страницы, файлы или сегменты в независимых сообщениях, которые фиксируют прогресс. Если нет, используйте строгие ограничения, безопасную отмену и процедуру проверки исчерпавших попытки задач.
Приоритет повышает риск повторения эффектов, когда отправитель повторно отправляет сообщение или потребитель даёт сбой после вызова внешнего API. Проектируйте идемпотентные обработчики: используйте стабильный ключ операции, сохраняйте состояние перехода и обеспечивайте, чтобы двукратная обработка имела тот же бизнес-эффект, что и однократная. Дедупликация брокера сообщений может сократить число дубликатов, но не заменяет идемпотентность в приложении и внешних интеграциях.
Отслеживайте ожидание, а не только размер очереди
Короткая очередь может скрывать проблему, если её самые старые сообщения ждут слишком долго или потребители постоянно дают сбой. Для каждого класса обслуживания измеряйте возраст самого старого сообщения, время от публикации до начала, длительность выполнения, процент ошибок, повторных попыток и задач, отправленных на проверку.
Дополняйте эти метрики активной параллельностью, глубиной, скоростью поступления и обработки, использованием соединений, временем работы зависимостей и полученными ограничениями частоты запросов. Наиболее полезные сигналы: ожидание в критическом классе превышает целевой показатель, массовая очередь растёт при ограниченной квоте, повторные попытки доминируют в трафике или зарезервированная мощность простаивает во время пиков другой категории.
Настраивайте оповещения по трендам и целевым показателям обслуживания, а не только по фиксированному числу сообщений. Тысяча сообщений может быть нормой при импорте; десять могут быть критичны, если это подтверждения заказов, ожидающие уже несколько минут.
Пример общего потока и список внедрения

Представьте платформу, обрабатывающую срочные заказы, уведомления и массовый импорт каталога. Заказы маршрутизируются в critical; транзакционные уведомления — в interactive; а импорт разбивается на страницы, отправляемые в bulk. Рабочие процессы заказов имеют зарезервированную мощность. Импорт имеет ограниченную параллельность и снижает темп при росте задержки базы данных. Уведомления соблюдают квоту провайдера с отложенными повторными попытками. Если процесс повторяется, ключ операции предотвращает создание двух резервирований или отправку двух изменений состояния.
Чтобы внедрить эту модель в существующее приложение:
- Составьте перечень обработчиков и назначьте класс обслуживания на основе срока, влияния и зависимости.
- Измерьте длительность, ожидание и ошибки до изменения маршрутизации.
- Сначала разделите критические и массовые потоки и зарезервируйте минимальную мощность.
- Определите лимиты параллельности по зависимостям и политики обратного давления.
- Сделайте бизнес-эффекты идемпотентными и ограничьте повторные попытки и время выполнения.
- Протестируйте пики нагрузки, отказ провайдеров и массовый входящий поток до активации нового распределения.
- Регулярно пересматривайте квоты и классы: приоритет — это бизнес-политика, которая меняется вместе с продуктом.
Желаемый результат состоит не в том, чтобы всё стало приоритетным, а в том, чтобы каждая задача получала согласованные мощность и срок, не превращая операцию большого объёма в блокировку для остального бизнеса.



