Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Система хранения #91

Open
kulakovt opened this issue Aug 17, 2019 · 6 comments
Open

Система хранения #91

kulakovt opened this issue Aug 17, 2019 · 6 comments
Labels

Comments

@kulakovt
Copy link
Member

kulakovt commented Aug 17, 2019

🐘 Code name: GitHubDB

Server является программой для управления Аудитом. С его помощью мы должны уметь читать и изменять данные о митапах, докладах, докладчиках и прочем.

Надёжным хранилищем для Аудита сейчас является GitHub. Можно и дальше использовать его для хранения всех данных. Он имеет ряд преимуществ перед сторонними решениями (MS SQL, MongoDB, SQLite и т.д.), которые нужно хостить, поддерживать, аутентифицировать и делать очень много другой избыточной работы.

У GitHub'а как надёжного хранилища сейчас есть ряд проблем, которые можно решить с помощью Server'а. Рассмотрим их подробнее.

Редактирование XML файлов

Для заполнения одного митапа нужно отредактировать десяток файлов, в соответствии со строгой схемой.

Это одна из основных задач которую решает проект Server (предоставляя удобный API) и DevActivator (обеспечивая интуитивный Web UI).

Хранение промежуточного состояния

Часто организация митапа состоит из множества шагов: поиск места, тренировка спикеров, написание анонса. Все эти операции могут быть сильно разнесены во времени. Но в master Аудита может попасть только полностью сформированный и отвалидированный митап. Необходимо иметь возможность надёжного хранения промежуточного, не полного состояния встречи.

Для этого идеально подходят GitHub Pull Request'ы. При создании нового митапа, сервер может создать Pull Request в репозитории Audit и обновлять информацию в нём по мере заполнения данных через API. Для того чтобы различать законченные Pull Request'ы, готовые к вливанию и события в процессе редактирования, можно воспользоваться стандартной практикой - начинать названия со слов "[WIP] " (work in progress). Или воспользоваться новым механизмом Draft Pull Requests.

Pull Request должен создаваться от имени оператора, который создаёт встречу. Это позволит полноценно интегрироваться с сервисом: вести дискуссию в комментариях, упоминать автора, учитывать всю работу в истории репозитория и личной истории каждого пользователя.

Идентификация правильного Pull Request'а

Специфика репозитория Audit заключается в том, что все изменения создаются только в рамках определённого бизнес процесса. Это позволяет полностью избежать конфликтов и однозначно идентифицировать нужный Pull Request во время редактирования информации. Идентификацию самого процесса можно сделать полностью на парсинге названия.

Рассмотрим несколько примеров того как определить нужный Pull Request (бизнес-процесс), имея только информацию о редактируемой сущности.

Создание нового митапа

Пример название для Pull Request'а: Add meetup Meetup.Id

Самый частый бизнес-процесс. Для его идентификации необходимо выяснить, какому митапу принадлежит сущность. Это можно сделать однозначно при изменении Meetup и Talk. C Speaker, Friend и Venue есть неоднозначность: они могут участвовать во множестве митапов. Решить её довольно легко: если во множестве возможных митапов существует тот на который сейчас есть активный Pull Request, значит изменения должны сохраниться в нём. Если подобного нет, то эта ситуация описывается в бизнес-процессе "Спонтанное редактирование".

Добавление артефактов митапа

Пример название для Pull Request'а: Add artifacts to Meetup.Id

Например слайдов, видео-записей, фотографий. В этом бизнес-процессе участвуют только сущности Talk и только добавление полей: CodeUrl, SlidesUrl, VideoUrl. Это позволяет однозначно определить митап. Обычно при выкладывании артефактов Pull Request создания этого митапа уже закрыт. В этом случае необходимо создать новый. Если бизнес-процесс "Создание митапа" ещё не закрыт (имеет открытый Pull Request), то данные должны добавляться именно в него (без создания нового Pull Request'а).

Спонтанное редактирование

Пример название для Pull Request'а: Update Entity.Id

Например смена работы докладчика, изменение логотипа компании, исправления опечаток в описании доклада и т.д. Этот вариант используется только если никакой другой не подошёл. В этом случае изменения не привязаны к какому-то отдельному митапу и должны храниться в отдельном Pull Request'е. В данном бизнес-процессе может участвовать только одна сущность, поэтому идентификация соответствующего места хранения тоже не должна вызвать проблем.

Ограничение на чтение данных

API GitHub'а довольно быстрое и стабильное. Но Audit использует иерархическую структуру сущностей т.е. для отображения одного митапа может потребованться десяток запросов. Это уже будет не быстро, особенно если мы говорим о данных для IntelliSense'а. Так же GitHub имеет ограничение на количество запросов к своему API.

Чтобы решить все эти проблемы нам нужно на сервере держать локальный, embeded, in memory кэш. Кэш должен строиться на старте приложения из GitHub'а и поддерживаться в процессе жизни приложения. Данные в нём могут быть представлены в денормализованной форме для обеспечения максимальной производительности чтения через API. При этом, редактирование должно остаться надёжным.

При редактировании данных, мы должны пройти следующую цепочку:

  1. API принимает и валидирует данные
  2. Данные записываются в InMemory Cache
  3. Данные записываются в соответствующий GitHub Pull Request
  4. API возвращает подтверждение об успешном сохранении информации

Кэш может изменяться не только через редактирования API Server'а, но и через редактирования GitHub репозитория (и его Pull Request'ов) напрямую. Поэтому программа должна синхронизировать данные (подписавшись на hook'и или периодически опрашивать GitHub репозиторий Audit'а) на предмет изменений и новых Pull Request'в, которые пришли не через Server API и соответственно перестраивать кэш.

Подобная архитектура позволит максимально увеличить скорость чтение данных. Ибо при этом не должно происходить обращений к GitHub API совсем, все данные будут отдаваться из кэша. А также мы получаем гарантированное сохранение данных в надёжном GitHub Pull Request'е.

@kulakovt kulakovt added the epic label Aug 17, 2019
@egorikas
Copy link
Contributor

Потенциально, не вижу проблем. Можно делать POC

@ilabutin
Copy link
Collaborator

Давайте сначала поймём как это может выглядеть (в плане архитектуры).

Насколько я вижу код сейчас схема взаимодействия у нас controllers->services->repositories.

Причем в слой services добавлено кэширование, поэтому фактически схема controllers->cached services -> services -> repositories.

Правильно ли я понимаю что мы добавляем новые repositories взамен текущих которые работают с БД?
Это выглядит вполне прямолинейным, но нам нужно будет научиться сбрасывать кэш (в cached services) на основе регулярного считывания текущего состояния github - это отдельный сервис или всё же лучше всю логику кэширования убрать в репозитории и отказаться от cached services слоя?

@kulakovt
Copy link
Member Author

Мне кажется, что логика кэширования должна быть спрятана в Repository по следующим причинам:

  1. только непосредственный провайдер данных из низкоуровневого хранилища (в нашем случае Repository) знает о том нужно вообще кэширование или нет. Например для FileSystemRepository оно нужно, а для InMemoryRepository не нужно.

  2. только Repository может знать когда сбрасывать кэш. Это может быть событие от FileSystemWatcher'а или web hook от GitHub'а.

@ilabutin
Copy link
Collaborator

Ок, принято. Совпадает с моим мнением :)

Значит, будем работать в этом направлении после того как разберемся с остальным.

@egorikas
Copy link
Contributor

egorikas commented Oct 1, 2019

Кэш, это наследие первой версии проекта, где все было поверх xml, я его не стал убирать, чтобы не взорвалось ничего.

@Sergey-Buyanov
Copy link
Contributor

Sergey-Buyanov commented Oct 1, 2019

Думаю, уровни кэша могут быть разные,
Кэш может быть и на уровне сервиса и на уровне репозитория.
Одно из свойств кэша, это быстройдействие, если в сервисе будет мало логики, результатов которые надо кэшировать, то можно пока ограничиться кэшем только на уровне репозитория.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants