Это минимальная реализация задания 1. Сервер возвращает захардкоденные ответы, без реального хранилища.
Скопируйте проект и выполните:
go mod download
go run ./cmd/serverПосле начала работы сервера, можно отправить запросы на него. Например:
# Через HTTP gateway
curl "http://localhost:8080/v1/posts?limit=10&offset=0" | jq
# С пользовательским заголовком
curl -H "x-user-id: user123" "http://localhost:8080/v1/posts?limit=5&offset=0" | jq
# Создать новый пост
curl -X POST "http://localhost:8080/v1/posts" \
-H "Content-Type: application/json" \
-H "x-user-id: alice" \
-d '{"body": "Это мой первый пост через HTTP API!"}' | jq
# Редактировать пост
curl -X PUT "http://localhost:8080/v1/posts/1" \
-H "Content-Type: application/json" \
-H "x-user-id: alice" \
-d '{"body": "Отредактированный текст поста"}' | jq
# Поставить лайк
curl -X POST "http://localhost:8080/v1/posts/1:like" \
-H "Content-Type: application/json" \
-H "x-user-id: bob" \
-d '{}' | jq
# Убрать лайк
curl -X POST "http://localhost:8080/v1/posts/1:unlike" \
-H "Content-Type: application/json" \
-H "x-user-id: bob" \
-d '{}' | jq
# Удалить пост
curl -X DELETE "http://localhost:8080/v1/posts/1" \
-H "x-user-id: alice" | jqТак же через браузер можно проверить его страничку
open http://localhost:8080/swagger/Для начала нужно утановить запустить Redis, для этого нужно установить его и ввести следующие комманды в терминал:
sudo apt install redis-server
redis-serverДалее установим и запустим PosgreSQL:
sudo apt install postgresql postgresql-contrib
sudo service postgresql startСоздадим таблицы в PosgreSQL и выдадим неоходимые права на сехму и на таблицы в ней:
# Очистить всё и создать заново
sudo -u postgres psql -c "DROP DATABASE IF EXISTS blog;"
sudo -u postgres psql -c "DROP USER IF EXISTS blog_user;"
# Создать базу и пользователя
sudo -u postgres psql -c "CREATE DATABASE blog;"
sudo -u postgres psql -c "CREATE USER blog_user WITH PASSWORD 'blog_password';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE blog TO blog_user;"
# Выдать права в базе blog
sudo -u postgres psql -d blog -c "GRANT ALL ON SCHEMA public TO blog_user;"
sudo -u postgres psql -d blog -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO blog_user;"
sudo -u postgres psql -d blog -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO blog_user;"
sudo -u postgres psql -d blog -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO blog_user;"
sudo -u postgres psql -d blog -c "CREATE EXTENSION IF NOT EXISTS \"pgcrypto\";"И мы должны получить следующий вывод:
DROP DATABASE
DROP ROLE
CREATE DATABASE
CREATE ROLE
GRANT
GRANT
GRANT
GRANT
ALTER DEFAULT PRIVILEGES
CREATE EXTENSIONДалее можно запускать сервер:
go run ./cmd/serverПосле того как сервер запустился можем проверить, работоспособность пробными запросами:
psql -h localhost -U blog_user -d blog -c "SELECT * FROM posts;"
psql -h localhost -U blog_user -d blog -c "SELECT * FROM authors;"Все теми же коммандами (curl'ми из начала редмишника) из первого дз можно проверить работоспособность сервера
Теперь попробуем создать пост и проверить сохраняется ли он в бд (для поста нужно заранее узнать айди вашего пользователя и вписать в соответсвующее поле):
# Вставить сгенерированный x-user-id, он не постоянный при разныъ сеансах
curl -v -X POST "http://localhost:8080/v1/posts" \
-H "Content-Type: application/json" \
-H "x-user-id: af448f1a-e198-4044-9f2c-4ca7493afc49" \
-d '{"body": "Это созданный пост!"}'
# Проверяем бд
sudo -u postgres psql -d blog -c "SELECT * FROM posts;"
sudo -u postgres psql -d blog -c "SELECT * FROM authors;"Видим, что при существующем айди в таблице появляется новый пост, а авторов остается то же количество, а при несущуствующем айди появляется новый автор, у которого появляется один пост, так что все работает как и планировалось
Для теста редактирования и удаления постов, можно воспользоваться кодом ниже:
curl -X PUT "http://localhost:8080/v1/posts/eb118ba7-097e-41ab-b133-5501348d8508" \
-H "Content-Type: application/json" \
-H "x-user-id: af448f1a-e198-4044-9f2c-4ca7493afc49" \
-d '{"body": "Этот пост заредачен!"}' | jq # Заменить пост айди на какой-нибудь пост из бд и юзер айди на юзера, который создал этот пост, причем если указать айди не автора поста, то пост нельзя будет поменять
curl -X DELETE "http://localhost:8080/v1/posts/fec1937b-efd4-4dd9-9e2a-61f8fd0169dc" \
-H "x-user-id: 51a424f8-5ce3-4849-9a60-39403fcb5ea6" | jq # Заменить пост айди на какой-нибудь пост из бд и юзер айди на юзера, который создал этот пост, причем если указать айди не автора поста, то пост нельзя будет удалить
curl -X GET "http://localhost:8080/v1/posts" | jq # Получить все посты
Аналогично можно проверить все варианты разных ответов функций, которые сохранились с предыдущего дз.
Теперь проверим Redis:
# Ставим лайк от пользователя bob
curl -X POST "http://localhost:8080/v1/posts/ef21f5ea-2716-497d-a512-753b80a509a2:like" \
-H "Content-Type: application/json" \
-H "x-user-id: a24d1dca-73d6-437d-8714-8e5933fcf0ab" \
-d '{}' | jq
curl -X POST "http://localhost:8080/v1/posts/ef21f5ea-2716-497d-a512-753b80a509a2:unlike" \
-H "Content-Type: application/json" \
-H "x-user-id: a24d1dca-73d6-437d-8714-8e5933fcf0ab" \
-d '{}' | jqПользователь может поставить лайк только один раз, потом будет выдаваться ошибка. Пользовтель может убрать лайк только с того поста, который он пролайкал. Тоесть система лайков имплементированна верно.
Для общего числа лайкнувших пост использован тип данных hash
// post_likes: {post_id -> like_count}
HGET post_likes "ef21f5ea-2716-497d-a512-753b80a509a2"Для флага 'лайкнул ли пользователь' использован тип данных set
// post_likes_users:{post_id}: {user_id1, user_id2, ...}
SISMEMBER post_likes_users:ef21f5ea-... a24d1dca-...Кеширование главное страницы присутствует:
time curl -s "http://localhost:8080/v1/posts?limit=10&offset=0" > /dev/null # Первый запрос будет отображаться в терминале, в котором запущен сервер
time curl -s "http://localhost:8080/v1/posts?limit=10&offset=0" > /dev/null # Второй запрос не будет отображаться в терминале и будет быстрееЧтобы оптимальнее сделать получение персонализированных флагов лайкнутости нужно вместо полноценного цикла (тогда будет 10 запросов подряд) использовать пайплайн, тогда мы делаем всего один сетевой запрос. Для этого пайплайн использован в следующих функциях:
# Использование pipeline в GetLikedFlags
pipe := r.client.Pipeline()
for _, postID := range postIDs {
cmds[postID] = pipe.SIsMember(ctx, key, userID)
}
_, err := pipe.Exec(ctx) # один вызов
# Использование pipeline в GetLikesCount
pipe := r.client.Pipeline()
for _, postID := range postIDs {
cmds[postID] = pipe.HGet(ctx, "post_likes", postID)
}
_, err := pipe.Exec(ctx) # один вызовДз небольшое и не затрагивает функционал проекта, только немного изменяет его. Вместе со стартом сервера будем логгировать запросы в консоль, собирать метрики в prometheus
Для проверки логгирования в консоли, можно дать серверу запросы и увидеть логи, например:
# Запрос всех постов
curl "http://localhost:8080/v1/posts?limit=5" | jq
# Сделать пост
curl -X POST "http://localhost:8080/v1/posts" \
-H "Content-Type: application/json" \
-H "x-user-id: test-user-123" \
-d '{"body": "Тест логирования"}' | jq
# Лайкнуть пост
curl -X POST "http://localhost:8080/v1/posts/ef21f5ea-2716-497d-a512-753b80a509a2:like" \
-H "Content-Type: application/json" \
-H "x-user-id: a24d1dca-73d6-437d-8714-8e5933fcf0ab" \
-d '{}' | jqВот пример логгирования в консоль, в консоли в начале лога написанно чего это лог, gRPC или Redis'a.

Для проверки метрик Prometheus:, нужно пройти по http://localhost:8080/metrics, там будут лежать все логи.
Видим, что все запросы попадают в bucket "le=0.005". Ошибки в like и unlike потому, что я намеренно ставил два лайка и убирал два лайка с одного и того же аккаунта.
Докеризируем наш сервис, для этого напишем Dockerfile и docker-compose.yml, после чего нужно исполнить
sudo docker-compose up -buildПосле чего сервис скомпилируется в бинарник и запустится в контейнере:
Добавлены тесты для бд и кэша с дефолтными параметрами и с недефолтными, для тестирования нужно:
go test ./internal/service -vДалее в отдельной директории client/ делаем клиента который первой фазой параллельно 100 горутинами будет создавать посты, далее 1000 горутинами с рандомными limit и offset будет делать запросы. После чего напишем для него собственные Dockerfile docker-compose и go.mod. После чего сначала запускаем сервер коммандой
sudo docker compose up -d blog-service postgres redisИ далее запускаем клиента (если написать просто docker compose up --build, то клиент прогонит все быстрее чем сервер поднимер редис и постгрес и будет 0 созданных постов)
sudo docker compose run --rm blog-clientТогда получим:
Получим, что примерно половина запросов выполнились до таймаута. Таким образом сервер протестирован с клиент в отдельном контейнере как требовалось в тз.





