Асинхронная интеграция через очередь и фоновые задачи
На одном из legacy проектов выполнил оптимизацию процесса.
Изначально он выглядел так: • Сервис1 создает объект в своей бд; • Сервис1 пишет в буферную таблицу Сервиса2 данные, необходимые для создания этого объекта; • Сервис1 вызывает dll для обработки буферной таблицы и создания объектов в Сервисе2.
Столкнулся с проблемами: • синхронный режим вызова dll; • ошибка при обработке одного объекта блокирует обработку последующих; • в случае ошибки - ручной retry по нажатию кнопки на форме просмотра каждого объекта; • нет механизма актуализации данных в буферной таблице при повторной обработке объекта после ошибки;
Перед собой поставил 4 ключевые задачи: 1. независимая интеграция одного объекта; 2. асинхронная архитектура; 3. актуализация информации об объекте на момент его обработки; 4. автоматический механизм retry;
Что сделал: • в бд Сервиса1 добавил таблицу-очередь. В одной транзакции происходит создание объекта и его постановка в очередь со статусом “Pending”. • вызов dll заменил на вызов метода web api, в котором стартует фоновая задача Hangfire. • в фоновой задаче считывается актуальная информация об объекте, вставляется в буферную таблицу и вызывается логика создания объекта в Сервисе2. После выполнения фоновой задачи обновляется статус в таблице-очереди.
Решение обеспечивает: • слабую связанность: Сервис1 не ждет ответа и не зависит от доступности Сервиса2. • гарантию доставки задачи с retry: Hangfire хранит задачи в бд и перезапускает при сбоях (retry). Даже если Сервис2 не доступен - задача не потеряется. • идемпотентность на стороне Сервиса2: защита от дублей при повторных запусках (retry-safe). • прозрачность: дашборд Hangfire позволяет отслеживать зависшие или упавшие задачи. • снижение времени ожидания пользователя при создании объекта в Сервисе1.
Нюансы архитектуры: • нет атомарности: если вызов Web API упадет после сохранения объекта в бд и постановки в очередь, то задача не попадет в Hangfire. Статус pending повиснет навсегда. Т.е. появляется окно рассогласования между записью в очередь и постановкой задачи в обработку. Решается фоновым обработчиком, который сканирует зависшие pending задачи. • идемпотентность на стороне Сервиса1: во время интеграции объекта на этапе получения актуальных данных о нем, в теории, объект может быть удален в Сервисе1. Тогда интеграция упадет в ошибку. Нужно либо блокировать изменения, либо кешировать данные.
· 04.04
Отличный разбор! Особенно ценно, что честно описал нюансы — окно рассогласования между очередью и Hangfire — это то, о чём многие забывают в статьях. В Node.js/NestJS-мире похожий паттерн с BullMQ + Redis: transactional outbox в одной транзакции с бизнес-операцией. По поводу идемпотентности — мы делаем idempotency key на уровне сообщения, чтобы retry был абсолютно безопасным. Какой retry policy используешь в Hangfire — экспоненциальный backoff?
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён
· 04.04
Спасибо за обратную связь и что поделился своими инструментами!
Да, такой retry policy, в hangfire он стандартный.
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
ответ удалён