Асинхронная активация подарочных карт: продолжение истории

После автоматизации склада активность на сайте выросла. В пиковые дни количество активаций доходило до десятков тысяч в сутки. Синхронная активация начала давать сбои: задержки, дублирование запросов, ошибки в данных. Мы перевели активацию на асинхронную обработку через RabbitMQ и Laravel Jobs, увеличили количество воркеров и подключили WebSockets для мгновенного обновления баланса. Нагрузка снизилась, дубли исчезли, пользователь видит результат сразу.

Асинхронная активация подарочных карт: продолжение истории

Напомним: с чего всё началось

В прошлой статье мы рассказывали, как автоматизировали склад подарочных карт и убрали ручной труд: заменили Excel на админ-панель, внедрили активацию без менеджера, отчёты и API для 1С.

Тогда казалось, что задача решена. Но у этой истории оказалось продолжение, и оно про то, что происходит, когда автоматизация начинает работать слишком хорошо.


Рост активности: проблема, которую мы не планировали

После запуска автоматизации активность на сайте начала расти. Клиенты массово пользовались активацией подарочных карт — это было ожидаемо и приятно.

Но в пиковые моменты — праздничные дни — количество активаций в сутки доходило до нескольких десятков тысяч.

И тут проявилась обратная сторона успеха.


Как работала активация: синхронный подход

Изначально активация была синхронной:

  1. Человек вводит код карты.

  2. Отправляется запрос на бэкенд.

  3. Выполняется бизнес-логика активации, включая запросы в СУБД.

  4. Клиенту возвращается ответ.

Для небольших объёмов это работало отлично. Но при большом количестве одновременных запросов начались проблемы:

  • Задержки — из-за ограничений мощности и невозможности параллельной обработки синхронных операций.

  • Дублирование запросов — в пиках от клиента поступали два идентичных запроса, и оба проходили. Это вызывало проблему с данными и приводило к ошибкам.

Самое неприятное в дублях: пользователь мог получить двойное начисление, а система — рассогласованные данные. Это уже не просто «медленно», это инцидент.


Решение: асинхронная обработка через RabbitMQ и Laravel Jobs

Мы решили кардинально поменять подход к активации. Все процессы, по которым были просадки, вынесли на асинхронную обработку.

Что применили:

  • RabbitMQ — брокер очередей для управления задачами.

  • Laravel Jobs — стандартный механизм очередей фреймворка.

Как изменился пользовательский сценарий:

  1. Пользователь вводит код карты.

  2. Проходит валидация (проверка формата, срока действия и т.д.).

  3. Если валидация пройдена — выводится сообщение: «Ваша активация принята, ожидайте поступления средств».

  4. Задача уходит в очередь, где обрабатывается асинхронно.

Это сразу сняло нагрузку с синхронного пути и убрало проблему с дублирующимися запросами.


Новый вызов: одного потока не хватило

Асинхронная обработка запускалась в один поток. Этого хватало для стабильности, но не для скорости.

Пользователь ждал поступления средств дольше, чем хотелось. Для «мгновенной» активации одного воркера было недостаточно.

Что мы сделали:

  • Увеличили количество потоков для обработки активаций.

  • Проблема с задержкой ушла — активации стали обрабатываться быстро даже в пиковые дни.


Новая проблема: пользователь не видит баланс «здесь и сейчас»

Асинхронность решила проблемы с нагрузкой и дублями, но создала новую проблему пользовательского опыта.

Раньше: пользователь активировал карту и сразу видел обновлённый баланс.
Теперь: пользователь видит сообщение «ожидайте поступления средств» — и не понимает, когда именно деньги появятся на счёте.

Это расстраивало пользователей. Ожидание без обратной связи всегда воспринимается хуже, чем мгновенный результат — даже если фактически обработка занимает секунды.


Решение: WebSockets для мгновенного обновления баланса

Мы подключили WebSockets — технологию, которая позволяет серверу отправлять данные клиенту в реальном времени, без необходимости обновлять страницу.

Как это работает:

  1. Пользователь отправляет запрос на активацию.

  2. Задача уходит в очередь.

  3. Как только воркер обрабатывает активацию — сервер транслирует событие через WebSocket.

  4. Баланс в шапке сайта обновляется автоматически — без перезагрузки страницы.

Пользователь видит: «Активация принята» → через секунду баланс меняется. Ощущение мгновенности вернулось, хотя технически процесс остался асинхронным.


Результат: что изменилось

Главный итог: мы уменьшили нагрузку на сайт, убрали задержку активации для сотрудников, решили ошибку с дублирующимися запросами — и при этом сохранили для пользователя ощущение мгновенного результата.


Стек

  • Backend: Laravel (PHP)

  • Очереди: RabbitMQ + Laravel Jobs

  • Real-time: WebSockets

  • База данных: MySQL


Что мы вынесли из этой истории

1. Успех автоматизации — это не финиш, а новый старт

Рост активности — это хорошо. Но он открывает проблемы, которых не было при малых объёмах. К этому нужно быть готовым.

2. Синхронность — враг пиковых нагрузок

Всё, что может быть асинхронным, должно быть асинхронным. Это снимает нагрузку и убирает целый класс ошибок (например, дублирование запросов).

3. Асинхронность без обратной связи — плохой UX

Пользователю не важно, как устроена система внутри. Ему важно видеть результат. WebSockets — простой способ вернуть ощущение мгновенности.

4. Масштабирование — это итеративный процесс

Сначала один воркер, потом несколько. Сначала синхронно, потом асинхронно. Сначала без real-time, потом с WebSockets. Не нужно строить идеальную систему сразу — нужно решать проблемы по мере их появления.


Вместо заключения

Эта история — про то, что хорошая автоматизация всегда ведёт к росту, а рост — к новым вызовам. Мы прошли путь от синхронной активации к асинхронной, от одного воркера к нескольким, от «ожидайте» к мгновенному обновлению баланса.

И это, скорее всего, не конец. Но именно так и работает сопровождение продукта: не «сделали и забыли», а развиваем и решаем проблемы по мере роста.

Обсудим проект

Расскажите о задаче — оценим за пару дней

Контакты