Entity state transfer



В микросервисной архитектуре часто возникает задача, чтобы один микросервис реагировал на изменения сущностей другого микросервиса. Для примера возьмем следующую задачу:



1. Есть ticket service, хранящий обращения пользователей. Тикет задается тремя полями: id — идентификатор обращения, status — текущий статус OPEN / CLOSED и assignee — текущий оператор, обрабатыващий тикет



{

“id”: 123,

“status”: “OPEN”,

“assignee”: null

}




2. Есть chat service, который связывает обращения пользователей с оператором, ботом и т.д. Он должен как-то реагировать на изменения тикета



Возникает вопрос — как передавать изменения стейта



1. Синхронный подход



При изменении тикета ticket service синхронно дергает ручку в chat service, которая обработает изменения. Самый простой в реализации подход, но возникает проблема с high-coupling — в случае недоступности chat service будет недоступен и ticket service. Однако они должны уметь существовать в отдельности друг от друга, и доступность одного сервиса не должна влиять на доступность другого



2.1. Асинхронный подход: id



{

“id”: 123

}




Ticket service отправляет эвент, говорящий, что “что-то изменилось у тикета с определенным id”. Далее chat service, получая этот эвент, синхронно идет в ticket service и получает актуальный стейт. Такой подход хорош тем, что он охватывает сразу все изменения тикета, а также позволяет особо не думать про порядок эвентов — тк мы все равно сами ходим за актуальным стейтом. Из минусов — повышенная нагрузка на чтение на ticket service



2.2. Асинхронный подход: only change



{

“id”: 123,

“status”: {

“old”: “OPEN”,

“new”: “CLOSED”

}

}




Ticket service отправляет эвент, говорящий, что конкретно изменилось. Например status: OPEN -> CLOSED. Такой подход хорош тем, что отправляются лишь минимальный необходимый набор данных, но здесь уже нужно думать про порядок эвентов — потому что может быть важно обрабатывать изменения status и изменения assignee ровно в том порядке, в котором они произошли в тикетной системе



2.3. Асинхронный подход: snapshot



{

“id”: 123”,

“status”: “CLOSED”,

“assignee”: “operator_login”,

“snapshotTimestamp”: “2024-11-12T13:14:15Z”

}




Ticket service отправляет эвент со снапшотом текущего тикета. Из плюсов — не нужно синхронно ходить за стейтом тикета, он уже полностью есть в эвенте; особо не нужно думать про порядок — можно хранить timestamp последнего обработанного снапшота, и если приходит более ранний, то просто игнорируем. Из минусов — хранение в брокере большего объема информации