Как спроектировать сервис для проверки паспорта с длительной проверкой
Что проверяют
Умеете ли вы превратить долгую синхронную операцию в асинхронный процесс с понятным статусом и не потерять заявку при сбоях. Уточняют обычно так: что будет, если внешний источник проверки лёг на час, и как не проверить один паспорт дважды.
Как отвечать
Сначала уточните требования: сколько заявок в час, сколько длится проверка (секунды, минуты или сутки с ручной модерацией), какие ограничения у внешнего источника. Дальше схема:
- приём заявки:
POST /verificationsсохраняет запись со статусомpendingи сразу отвечает202 Acceptedс идентификатором. Клиент передаёт заголовокIdempotency-Key, чтобы повторное нажатие не создало вторую заявку; - публикация задачи: запись в базу и отправка в брокер должны быть согласованы. Надёжный вариант это transactional outbox: задача пишется в ту же транзакцию, отдельный процесс переносит её в RabbitMQ или Kafka;
- воркеры: Celery,
arqилиdramatiq, с ретраями, экспоненциальной задержкой и таймаутом на вызов внешнего API. После исчерпания попыток задача уходит в dead letter queue и на ручной разбор; - статусы:
pending,in_progress,approved,rejected,failed. Переходы только вперёд, каждый пишется в журнал для аудита; - обратная связь: клиент опрашивает
GET /verifications/{id}или получает вебхук, пуш, событие по WebSocket; - данные: паспорт это персональные данные, значит шифрование полей, минимальный срок хранения, маскирование в логах и соблюдение 152-ФЗ.
Добавьте circuit breaker на внешний источник: при массовых отказах воркеры перестают его долбить, а заявки спокойно ждут в очереди.
Где спотыкаются
Выполняют проверку прямо в обработчике запроса и держат HTTP-соединение открытым. На первом же медленном ответе источника у веб-сервера кончаются воркеры.
Не думают об идемпотентности: при повторной доставке сообщения проверка запускается второй раз, а обращение к внешнему сервису часто платное.
Пишут номера паспортов в логи и трассировки открытым текстом, и персональные данные расползаются по системам, где их никто не защищает.