Какие есть стратегии одновременной работы из sync и async входными точками данных, как синхронизировать роботу над одной сущностью?
Например у меня есть sync(синхронный) REST ендпоинт и async(асинхронный) REST ендпоинт(который сохраняет данные и только через пару минут обрабатывает).
Может быть такое что:
- пришел async запрос -> взял данные в обработку
- пришел sync запрос и отработал успешно
- запускается async джоба c данными из пункта 1
и тут вопрос: она должна упасть или sunc запрос не должен пройти так как к нам пришел async запрос раньше?
Какие есть стратегии одновременной работы из sync и async?
UDP: сущность = анкета - с статусом (NEW, DONE, PROCESS, ERROR) и своим жизненным циклом (то есть сначала один человек ее заполняет потом, другой человек подтверждает что все правильно, а 3-й обновляет и навешивает цену причем все эти люди работают асинхронно с анкетой через сторонний сервис), а синхронно можно отменить эту анкету.
То есть у меня
- пришло событие и мы только сохраняем в БД
- выполняем отмену анкеты синхронно
- должны обработать событие, но анкета неактуальная и падает обработка
Ответы (2 шт):
Давайте я попробую перефразировать и ответить. Забудьте про синхронностью и асинхронность.
Есть объект и его изменяют 2 процесса.
- Первый процесс взял копию данных на обработку.
- Второй процесс взял копию данных обработал и записал изменения.
- Первый процесс записал изменения или нет изменения.
Что должно быть так или не так в третьем случае? Все зависит от логики. Возможные ситуации.
- Кто последний тот и молодец. Процесс не проверяет изменяемые данные.
- Кто успел тот молодец. Процесс проверяет данные перед сохранением и может получить данные устарели.
Оба варианта существует и применяются на практике повсеместно. Который правильно а который нет всё исходит из логики. К примеру. Вы изменяет данные учётной записи из 2х мест одновременно чисто гипотетически. Если вы меняете имя то логично что кто последний тот и молодец, а вот с паролем уже не совсем так.
Фундаментальная проблема не в том, что есть sync/async, а в том, что одновременно происходят два параллельных процесса, которые изменяют одни и те же данные. Т.е. точно такая же проблема возникнет, даже в случае если у вас все методы синхронные, но их могут вызывать несколько клиентов параллельно.
Есть три основные стратегии разрешения конфликтов при одновременных изменениях:
- игнорировать конфликты. Грубо говоря, каждый процесс перезаписывает данные и то, что записали до него может потеряться.
- запрещать изменение, если данные модифицированы параллельно. Один из вариантов - это в момент записи данных в хранилище (грубо говоря в БД), определять, что данные были параллельно изменены и завершать операцию с ошибкой.
- делать слияние. Если при сохранении случился конфликт, то пробуем автоматически выполнить операцию заново с учетом текущего состояния данных, либо попросить пользователя разрешить конфликты.
Какую из этих стратегий использовать, зависит от сути операций. Для каждой операции нужно ответить на вопрос "а как правильно должна отработать операция, если данные которые она читает и модифицирует изменились параллельно?" Иногда это может потребовать изменить API операции.
Например, для операции пополнение банковского счета, вместо использования общей операции типа updateAcccount, которая получает все поля счета, можно передать только суму пополнения (т.е. операция становится более сфокусированной topUpAccount). В таком случае операцию можно перезапустить автоматически при конфликте (т.е. использовать вариант 3). Понятно, что нужно перечитать данные и убедиться, что при новом изменении не случилось конфликта опять.