Асинхронная интеграция через очередь и фоновые задачи

На одном из 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. Тогда интеграция упадет в ошибку. Нужно либо блокировать изменения, либо кешировать данные.

Асинхронная интеграция через очередь и фоновые задачи | Сетка — социальная сеть от hh.ru