Синхронное и асинхронное взаимодействие - Обработка с транзакцией 

Page / - Изменено Alexandr Fokin в 2020/08/09 15:23 

Обработка с транзакцией 
Изменено Alexandr Fokin
в 2020/08/09 15:23

Оглавление

 	Ситуация:
Имеется очередь, из которой приложение читает данные и обрабатывает их. Рассмотрим пример, что приложение имеет следующий цикл обработки сообщения:
1) Взять сообщение из очереди
2) Попытаться выполнить некоторый набор действий на основе данных из сообщения.
Отметим, что обработка сообщения может завершиться как успешно, так и с ошибкой.	 	
 	1]
1) Получаем сообщение
2) Выполняем коммит сообщения (при следующем чтении на вход пойдет следующее сообщение)
3) Выполняем обработку	Мы теряем сообщение, в случае если его обработка не завершилась успешно.	
 	2]
1) Получаем сообщение
2) Выполняем обработку
3) Если п.2 выполнен успешно, то выполняем коммит сообщения (при следующем чтении на вход пойдет следующее сообщение)	В случае, если после выполнения 2 пункта наше приложение упадет (не успев выполнить пункт 3), то при повторном запуске мы обработаем то-же самое сообщение второй раз.	
 	Вопросы
1) Является ли повторная обработка одного и того же сообщения допустимой для нашей системы.
2) Является ли потеря данных из одного из сообщений критичной для нашей системы.
3) Возможно в нашей системе производитель сообщение, генерирует сообщени3) Возможно в нашей системе производитель сообщение, генерирует сообщен3) Возможно в нашей системе производитель сообщение, генерирует сообщение повторно через некоторой промежуток времени, если фиксирует, что предыдущее сообщение не было обработано.	 	
 	Более надежное, но более тяжелое решение:
Использование подхода номер 2 совместно с каким-либо более продвинутым механизмом транзакций. Т.е в случае падения приложения транзакция не будет завершена успешно.
Но есть риск если у нас выполняются 2 действия:
1) коммит транзакции в базе, 2) коммит сообщения. (или в порядке 2, 1)
В случае падения приложения между указанными шагами, мы все равно можем получить
либо потерю сообщения (закоммитили сообщение, но не завершили транзакцию),
либо повторную обработку (завершили транзакцию, но не закоммитил сообщение).
Хоть и вероятность такого события в целом крайне мала. (зависит от системы)	 	
 	Замечание: на текущий момент отношу проблему к Dual write problem.
По хорошему у каждого запроса или хотя бы сообщения должен быть уникальный ключ. Использую его, транзакцию, таблицу с уникальным индексом можно добиться гарантии, что сообщение будет обработано только единожды. Транзакция БД позволяет атомарно зафиксировать и изменения и факт обработки сообщения (по его ключу).
Отдельный вопрос: хотим ли мы использовать очередь для приостановки обработки в случае ошибок. Зачастую мы не хотим останавливать обработку из-за одной ошибки. В таком случае важно сохранить проблемное сообщение, но при этом сделать так чтобы обработчик продолжил обрабатывать последующие сообщения.
Возможен вариант, когда сообщение просто записывается в БД в статусе ожидает обработку. И фоновый обработчик разбирает таблицу и обрабатывает необходимые строки.