Skip to content

moolcoov/expressionist

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Expressionist

Проект для Лицея Академии Яндекс

В случае ошибки или при любых других вопросах пишите сюды @moolcoov

2-ая часть задания

  • Сохранение в базу данных
  • Поддержка разных пользователей
  • Общение агента и оркестратора с помощью gRPC

Установка

Docker

Для начала на вашем компьютере должен быть установлен Docker. Как его установить написано в документации.

Клонирование репозитория

Далее необходимо клонировать репозиторий с кодом

git clone https://github.com/moolcoov/expressionist.git

Build

После этого нужно создать билд с помощью Docker Compose

docker-compose build

P.S Этот процесс может занять довольно много времени ☕

Запуск

После этого можно запускать проект

Для того чтобы запустить все сервисы:

docker-compose up -d

Для того чтобы запустить еще агентов:

docker-compose scale agent=3

Вместо 3 можно подставить любое число, сколько агентов вы хотите.

После этого можно открыть localhost:3000 для доступа к веб-версии или получить прямой доступ к оркестратору через localhost:8080

Тестовый сценарий

Откройте сайт и зарегистрируйтесь.

Далее, на главной странице можно будет создать выражение. Пример: 1024 / 2 + 4 * (2 + 3). Спустя некоторое время выражение будет подсчитано, и ответ отобразится автоматически.

Чтобы посмотреть агентов, перейдите на страницу "Агенты" (/agents). Чтобы изменить настройки, перейдите на страницу "Настройки" (/settings).

Чтобы войти в другой аккаунт или зарегистрировать новый, нажмите на кнопку выйти в правом верхнем углу.

На чем оно написано

1. Оркестратор

Оркестратор находится в директории /orchestra. Написан на Go.

Роутинг

Для роутинга изпользуется gorilla/mux. Все эндпоинты в субдиректории /routes.

База данных

База данных, в которую сохраняются выражения: PostgreSQL. Для доступа используется sqlx с драйвером pgx. Файл, в котором происходит подключение к бд /lib/postgres.go.

Кэш

Для кэширования результатов используется key-value база данных Redis. Для подключения применяется пакет go-redis. Файл, в котором происходит подключение /lib/redis.go

Связь с агентами

Для передачи выражений агентам используется RabbitMQ. Для подключения применяется amqp091-go. Файл /lib/redis.go.

Проверка активности агентов

Активность агентов проверяется в отдельной горутине с бесконечным циклом, которая каждые 10 секунд проверяет, не истекло ли время пинга у агентов.

go func() {
    for {
        agent.Agents.CheckAgents()
        time.Sleep(10 * time.Second)
    }
}()

Схема оркестратора выглядит так:

s

2. Агенты

Агент находится в директории /agent. Написан на Go.

Получение выражений

Агент получает выражения с помощью того же RabbitMQ. Схема подключения такая же, как и у оркестратора. /lib/redis.go.

Вычисление

Для вычисления используется измененная версия библиотеки go-shunting-yard.

Схема:

3. Клиент

Фронтенд написан на Typescript, с использованием фреймворка Next.js. Находится в директории /client.

Запросы к оркестратору

На серверной части запросы делаются с помощью официального API (добавление нового выражения, обновление настроек).

const res = await fetch(... ,{})

На клиентской части используется библиотека SWR (получение списка выражений, агентов, настроек).

const { data, error, isLoading } = useSWR(..., fetcher)

Схема:

Как оно работает (написано для версии 1 (без многопользовательности))

Запуск

Все настройки для PostgreSQL, Redis, RabbitMQ и т.д. находятся в файле .env

Оркестратор

При запуске оркестратор подключается к PostgreSQL (создает таблицу, если ее нет), Redis, открывает канал RabbitMQ. Также он объявляет настройки, которые получает из Redis под ключом _settings. (Если в редисе значений нет, он их создает).

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

Агент

При запуске агент генерирует uuid, регистрирует его у оркестратора, получает настройки, подключает RabbitMQ.

Далее запускает n горутин, с бесконечным циклом.
n определяется в переменной среды AGENT_GOROUTINES в файле .env.

В горутинах начинается принятие и обработка выражений. Также запускается горутина, которая пингует оркестратор и обновляет настройки, с задержкой в 30 секунд

Клиент

При запуске начинает обрабатывать запросы пользователя.

После запуска

Главная страница

После перехода на localhost:3000 открывается главная страница с полем для ввода и выражениями.

Когда фронтенд запрашивает выражения у оркестратора (/expressions), бэкенд идет в postgres и берет их оттуда.

После ввода выражения в поле ввода серверная часть фронтенда отправляет POST запрос на /new с полями выражения и даты отправки в теле запроса.

Оркестратор записывает данные в структуру, парсит выражение, проверяет нет ли в redis закэшированного значения.

Если оно есть, оркестратор сразу возвращает значение.

После в отдельной горутине (для быстроты ответа клиенту) если выражение не посчитанно, отправляется агентам через очередь RabbitMQ.

В заключение выражение добавляется в PostgreSQL.

Тем временем агент получает выражение, обновляет его статус на "в прогрессе" и начинает вычислять.

Сначала проверяется валидность выражения, если оно невалидно статус переводится на "errored" и обновляется у оркестратора (/submit)

Если оно валидно, выражение переводится в обратную польскую нотацию и вычисляется.

После этого, подсчитывается количество операций, считается время ожидания из полученных настроек, а потом

time.Sleep()

Я знаю, что можно было эффективнее сделать, разбивать выражения на подвыражения, считать их по разному, но времени уже не было 💥💥💥

В конце выражение с результатом отправляется на /submit
Там оно кэшируется в Redis

Страница агентов

На ней фронт запрашивает список агентов (/agents). Агент может быть активным и нет. После регистрации каждые 30 секунд агент должен присылать запрос со своим id на /ping.

Если он этого не сделал в течении 40+-10 секунд, агент становится неактивным. Из базы данных получаются все выражения, которые считаются в данный момент и прикреплены к этому агенту. Выражения снова отправляются другим агентам через RabbitMQ. Там оно считается другими агентами.

Если агент неактивен в течении определённого времени, указанного в настройках, он исчезает.

Все это проверяется в горутине с бесконечным циклом с задержкой 10 секунд.

Страница настроек

На ней фронт запрашивает настройки (/settings).

При изменении настроек серверная часть отправляет новые значения на /settings/update. Агент получит новые настройки в течении 30 секунд.

! Если настройки не изменились с первого раза, попробуйте обновить их еще раз.

Схема

Полная схема проекта выглядит так:

Итог

Я знаю, что можно было сделать намного лучше:

  • Разделять выражения
  • Оптимизировать код
  • Улучшить структуру

Но я считаю, что я устал, и это все, что нужно.

Ну в общем все, если что пишите. Не судите строго, всем бобра.

Смотрите, какой краб

by moolcoov 21/04/2024

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published