Для малого бизнеса с десятком чеков в день достаточно Telegram-бота. Но что делать маркетплейсу, обрабатывающему сотни или тысячи транзакций ежедневно? Последовательная обработка каждого чека по одному превращается в узкое горло: при 1 секунде на чек обработка 1000 чеков займёт больше 16 минут.
В этой статье мы разберём архитектуру системы для пакетной обработки чеков через API ProverkaCheka: от очередей задач и параллельной обработки до мониторинга и оптимизации производительности.
Почему последовательная обработка не масштабируется
При стандартном подходе ваш сервер отправляет один чек, ждёт ответ, обрабатывает результат и переходит к следующему. Вот как растёт время обработки:
| Чеков в день | Последовательно (1 сек/чек) | Параллельно (10 потоков) | Параллельно (20 потоков) |
|---|---|---|---|
| 100 | ~2 мин | ~10 сек | ~5 сек |
| 500 | ~8 мин | ~50 сек | ~25 сек |
| 1 000 | ~17 мин | ~100 сек | ~50 сек |
| 5 000 | ~83 мин | ~8 мин | ~4 мин |
Разница очевидна: параллельная обработка в 10-20 потоков превращает часовую задачу в минутную.
Архитектура пакетной обработки
Оптимальная архитектура для массовой проверки чеков состоит из четырёх компонентов:
- Приёмник чеков — принимает PDF-файлы от пользователей (через форму на сайте, email, или загрузку в систему) и помещает их в очередь.
- Очередь задач — хранит чеки, ожидающие обработки. Обеспечивает устойчивость: если сервер перезагрузится, чеки не потеряются.
- Воркеры — параллельные процессы, которые берут чеки из очереди и отправляют их в API ProverkaCheka. Количество воркеров определяет скорость обработки.
- Обработчик результатов — принимает ответы API, обновляет статусы в базе данных, отправляет уведомления.
Совет: Для простых сценариев (до 500 чеков в день) можно обойтись без полноценной очереди сообщений. Достаточно таблицы в базе данных со статусами «pending», «processing», «done», «error».
Управление rate limit
API ProverkaCheka имеет ограничения на количество запросов в единицу времени (rate limit). При его превышении вы получите HTTP 429 Too Many Requests. Чтобы эффективно работать в рамках лимита, используйте следующие стратегии:
Token bucket
Алгоритм token bucket — стандартный подход к rate limiting на клиентской стороне. Суть: у вас есть «корзина» с определённым количеством «токенов». Каждый запрос забирает один токен. Токены пополняются с фиксированной скоростью. Если токенов нет — запрос ждёт.
Экспоненциальный backoff
Если вы всё-таки получили 429 — не повторяйте запрос сразу. Используйте нарастающие задержки с элементом случайности (jitter):
- 1-я попытка: ожидание 1 + random(0, 0.5) секунд
- 2-я попытка: ожидание 2 + random(0, 1) секунд
- 3-я попытка: ожидание 4 + random(0, 2) секунд
- Максимум: 5 попыток, максимальная задержка 16 секунд
Мониторинг лимитов
Отслеживайте количество ошибок 429 в вашей системе. Если их доля превышает 5% — уменьшите параллельность. Если 429 ошибок нет совсем — можно аккуратно увеличить количество воркеров.
Обработка ошибок в пакетном режиме
При массовой обработке ошибки неизбежны. Важно правильно их классифицировать:
| Тип ошибки | Действие | Повторять |
|---|---|---|
| 400 Bad Request | Пометить как «ошибка формата» | Нет |
| 401 Unauthorized | Остановить все воркеры, проверить ключ | Нет |
| 402 Payment Required | Остановить воркеры, пополнить баланс | Нет |
| 429 Too Many Requests | Замедлить обработку | Да, с backoff |
| 500 Server Error | Вернуть в очередь | Да, с задержкой |
| Таймаут | Вернуть в очередь | Да |
| retry_after в ответе | Повторить через N секунд | Да |
При ошибках 401 и 402 остановите ВСЕ воркеры сразу. Нет смысла продолжать отправлять запросы, если API-ключ невалиден или кредиты закончились — это только создаст дополнительную нагрузку.
Dead Letter Queue — обработка неудачных чеков
Некоторые чеки могут не пройти обработку даже после нескольких попыток. Такие чеки нужно перемещать в отдельную очередь (Dead Letter Queue, DLQ) для ручного разбора.
Типичные причины попадания в DLQ:
- Повреждённый PDF — файл невозможно прочитать
- Нет QR-кода — PDF не содержит валидного QR-кода Kaspi
- Скриншот вместо PDF — пользователь отправил изображение, а не документ
- Устаревший чек — чек слишком старый и удалён из базы Kaspi
Рекомендуемая стратегия: после 3 неудачных попыток (для retryable-ошибок) переместите чек в DLQ с записью причины. Раз в день просматривайте DLQ и принимайте решения: повторить, запросить новый чек у клиента или списать.
Оптимизация производительности
Предварительная фильтрация
Перед отправкой в API проверяйте файлы на стороне клиента:
- Формат — только PDF (отклоняйте JPG, PNG, DOCX)
- Размер — не больше 5 МБ (типичный чек Kaspi весит 50-200 КБ)
- Дубликаты файлов — хешируйте содержимое и проверяйте, не загружался ли такой файл ранее
Connection pooling
Создание нового TCP-соединения для каждого запроса — дорогая операция. Используйте пул соединений (connection pool) для повторного использования соединений между запросами. В Python это делает библиотека requests.Session(), в Node.js — HTTP-агент с keep-alive.
Оптимальное количество воркеров
Слишком мало воркеров — медленная обработка. Слишком много — ошибки 429 и перегрузка сервера. Начните с 5 воркеров и постепенно увеличивайте, мониторя процент ошибок 429. Оптимальное значение обычно находится в диапазоне 5-20 воркеров.
Мониторинг пакетной обработки
При обработке тысяч чеков критически важно иметь прозрачность процесса. Отслеживайте следующие метрики:
- Размер очереди — сколько чеков ожидают обработки. Если очередь растёт — увеличьте параллельность
- Среднее время обработки — сколько секунд занимает одна проверка. Норма: 0.5-2 сек
- Процент ошибок — доля неудачных проверок. Выше 5% — повод для расследования
- Процент 429 — слишком высокий означает, что нужно снизить параллельность
- Размер DLQ — чеки, не прошедшие обработку. Требуют ручного внимания
- Расход кредитов — чтобы вовремя пополнить баланс и не остановить обработку
Совет: Настройте алерт на расход кредитов. Когда остаток опускается ниже дневной нормы — отправляйте уведомление ответственному, чтобы пополнить баланс до исчерпания.
Пример архитектуры для разных масштабов
100-500 чеков в день
Простая архитектура: таблица в PostgreSQL/SQLite как очередь, 5 воркеров в виде asyncio-задач или потоков. Без внешних зависимостей. Обработка полного объёма занимает 1-2 минуты.
500-2000 чеков в день
Redis или RabbitMQ как очередь задач, 10-15 воркеров, отдельный процесс для мониторинга. Dead Letter Queue для необработанных чеков. Дашборд с метриками в Grafana или аналоге.
2000+ чеков в день
Полноценная система: Celery/RQ с Redis, 15-20 воркеров, автоматическое масштабирование на основе размера очереди. Webhook-уведомления для реалтаймовых обновлений. Отдельная база данных для результатов проверок. Свяжитесь с нами для настройки выделенных лимитов API.
Итоги
Пакетная обработка — это не просто «отправить много запросов параллельно». Это архитектурный подход, включающий очереди задач, управление rate limit, обработку ошибок, Dead Letter Queue и мониторинг. Правильно спроектированная система обрабатывает тысячи чеков в день без ручного вмешательства и с минимальными потерями.
Начните с малого: 5 воркеров и простая очередь в базе данных. По мере роста объёмов добавляйте Redis, мониторинг и автоматическое масштабирование. API ProverkaCheka готов к любым объёмам — ваша задача грамотно управлять потоком запросов.