Реализация

EventSourcing

в Involve

Терминология

1. Запросы/Query

⚫От клиентов к серверу

⚫Идемпотентны

Обычная фьюча которая ждет результата

2. Команды/Command

От клиентов к серверу

Что-то меняют на сервере

Обычно не имеют возвращаемого результата

3. События/Event

Ходят внутри сервера или от сервера к клиенту

Основные моменты

Каналы

Источник событий с сервера

На каждый источник свой канал

Сервер постит события в канал

Все клиенты, которые слушают канал, получают эти события

Основные моменты

Модель на клиенте

⚫Хранит данные

Заполняется запросом к серверу

Подписывается на каналы

⚫Вьюхи отображают данные из моделей

⚫Модели персистентны

Основные моменты

Команды

Когда что-то меняем на клиенте - отправляем команду на сервер

Доставка команд должна быть гарантированной

Детали реализации

Команды

Гарантированная доставка

Клиент

Сервер

Положительный сценарий

Клиент

Сервер

Команды

Гарантированная доставка

Сервер не получил команду

Клиент

Сервер

Команды

Гарантированная доставка

Клиент не получил подтверждения

Id: 15

Id: 15

Команды

Порядок отправки

Без порядка отправки будет рассинхронизация

Команды отправляются строго по одной из очереди

Пока не принято подтверждение команды - следующая не отправляется

Команды сохраняются в очередь на клиенте

События и каналы

Связь событий и команд

Клиент

Сервер

Command

Event

События и каналы

Связь событий и команд

Нужно устанавливать связь между событием и командой, которая это событие сгенерировала

Событие можно использовать и как подтверждение команды

События и каналы

Связь событий и команд

Проблема - команда создает новый канал

1. Все-таки делать подтверждение

2. Иметь специальный канал типа "Сущности, созданные мной"

События и каналы

Порядок обработки событий

Без порядка будет рассинхронизация

Нужно хранилище необработанных событий.

⚫Если событие пропущено, то последующие ждут, пока не примется предыдущее

События и каналы

Порядок обработки событий

Как понять, что клиент пропустил событие?

Клиент

Сервер

События и каналы

Порядок обработки событий

Как понять, что клиент пропустил событие?

Сплошная нумерация событий внутри канала

Пока не понятно, что лучше

Передавать айди предыдущего в следующем событии

События и каналы

Порядок обработки событий

Как обработать пропуск события?

Инвалидация всей модели и запрос нового снапшота?

Использовать оба варианта?

Запросить недоставленные события и обработь их в правильном порядке?

События и каналы

Подписки на каналы

Скорее всего для многих сущностей каналы будут жить вечно

События и каналы

Подписки на каналы

Хранение подписок

1. Tолько клиент

2. Только сервер

⚫Плохо масштабируется

⚫Не зароутить сообщения на клиенте

3. И клиент и сервер

⚫Наш вариант!

События и каналы

Актуальности канала и модели

Проблема - как понять, что мы действительно приняли все события в канале?

Вдруг сервер нам что-то отправляет, а до нас это не доходит?

События и каналы

Актуальности канала и модели

Периодическое опрашивание клиентом сервера

Клиент периодически опрашивает сервер

⚫Актуальность проверяем по последнему принятому событию в канале

⚫Если события были - запросить недоставленные

Проблема - после длительного использования приложения может быть очень много каналов на клиенте

⚫Опрашивать не через константные промежутки времени, а в зависимости от того, насколько канал “горяч”

События и каналы

Актуальности канала и модели

Отправка событий с подтверждением от клиента

У каждого юзера есть свой актор

⚫Актор продолжает работу и когда клиент оффлайн

⚫Через него проходит доставка событий на клиент

При выходе онлайн актор синхронизирует состояние клиента и сервера

Минус - добавит состояния на сервер

Работа в оффлайне

Например, мы были оффлайн сутки, и написали в чат 100 сообщений

В это же время в том же чате написали 300 сообщений

Что делать?

Работа в оффлайне

Команды - просто  отдаем на сервер

Актуализируем каналы на клиенте

Как быть с большим расхождением модели на клиенте и сервере?

Работа в оффлайне

Расхождение клиента и сервера

Инвалидация всей модели и запрос нового снапшота?

Пытаться кусками подтягивать снапшоты?

Всегда подтягивать события?

Работа в оффлайне

Расхождение клиента и сервера

1. Если событий мало - сервер отправляет новые

⚫Модель либо инвалидируется

2. Если событий много

⚫Либо подтягивается новый снапшот

Конкретное поведение зависит от модели

Работа в оффлайне

Что делать с большим количеством пропущенных событий, когда мы решаем, что проще перекачать снапшот?

Работа в оффлайне

1. Забиваем

⚫Как определить степень старости?

2. Забиваем только на старые

⚫Не старые надо перекачать

3. Показать сообщение юзеру - "У вас там-то много событий"

Что еще нужно учитывать

1. У каждого юзера может быть несколько клиентов

2. Нужно будет везде продумывать batch processing

3. Возможно часть проблем не актуальна из-за гарантий Web-socket

4. В оффлайне будем использовать пуш уведомления

Выводы

1. Очень много проблемных мест

2. Стараться больше опираться на снапшоты и запросы

3. ИМХО - в альфе лучше сделать только онлайн и считать, что у нас всегда все гарантированно доставляется.

Реализация ES в Involve

By Yury Badalyants

Реализация ES в Involve

  • 339