This commit is contained in:
irylkov
2025-03-21 09:40:42 +03:00
commit bbb7597e17
24 changed files with 457 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea
bin

4
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,4 @@
include:
- project: 'go/classroom-18/students/base'
ref: master
file: '.gitlab-ci.yml'

65
.golangci.yaml Normal file
View File

@@ -0,0 +1,65 @@
# More info on config here: https://golangci-lint.run/usage/configuration/#config-file
run:
concurrency: 8
timeout: 10m
issues-exit-code: 1
tests: true
output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
linters-settings:
govet:
enable:
- shadow
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
linters:
disable-all: true
enable:
# - dupl - it's very slow, enable if you really know why you need it
- errcheck
- goconst
- goimports
- gosec
- govet
- ineffassign
- gosimple
- staticcheck
- revive
- typecheck
- unused # will be used insted of varcheck + deadcode + structcheck. More info https://github.com/golangci/golangci-lint/issues/1841
issues:
exclude-dirs:
- bin
- vendor
- var
- tmp
exclude-files:
- \.pb\.go$
- \.pb\.gw\.go$
- \.pb\.scratch\.go$
- \.pb\.goclay\.go$
exclude-use-default: false
exclude:
# _ instead of err checks
- G104
# for "public interface + private struct implementation" cases only!
- exported func .* returns unexported type .*, which can be annoying to use
# can be removed in the development phase
- (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)
# not for the active development - can be removed in the stable phase
- should have a package comment
- don't use an underscore in package name
# EXC0001 errcheck: Almost all programs ignore errors on these functions and in most cases it's ok
- Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
- should check returned error before deferring

6
Makefile Normal file
View File

@@ -0,0 +1,6 @@
include make/lint.mk
include make/build.mk
lint: cart-lint loms-lint notifier-lint comments-lint
build: cart-build loms-build notifier-build comments-build

119
README.md Normal file
View File

@@ -0,0 +1,119 @@
# Шаблон репозитория для реализации проекта на курсе Route 256
Поздравляем с зачислением на курс "Продвинутая разработка микросервисов на Go"! Надеемся, что процесс обучения будет
увлекательным, а полученные знания пригодятся в работе!
В рамках курса вам предстоит разработать проект– копию Озона в миниатюре. Не нужно пугаться, ведь на этом пути вас
будет сопровождать команда преподавателей и тьюторов. Работа над проектом будет разбита из 8 модулей, каждому из
которых, посвящены две лекции и одно практическое занятие. Действующие инженеры Озона поделятся своим опытом и обратят
внимание на важные аспекты, которые неизбежно возникают при разработке высоконагруженных распределенных систем. По
окончании каждого модуля будет предложено реализовать ту или иную часть из курсового проекта, имеющую непосредственное
отношение к теме модуля.
Желаем успехов в прохождении курса!
# Работа над курсовым проектом
## Инициализация проекта
Для работы над курсовым проектом необходимо выполнить инициализацию репозитория:
1. Открыть репозиторий https://gitlab.ozon.dev/go/classroom-18/students/homework-draft (вы уже в нем);
2. Создать копию данного репозитория https://gitlab.ozon.dev/go/classroom-18/students/homework-draft (форк проекта в свой
приватный репозиторий (см. рис. 1));
3. Разорвать связь с шаблонным репозиторием, для этого в GitLab необходимо выполнить: Settings Advanced Remove
fork relationship (см. рис. 2 и 3);
4. Добавить тьютора в Members проекта. Для этого: Project information Members Invite member, пригласить своего
тьютора с правами Maintainer (см. рис. 4, 5 и 6).
<em><strong>
Обрати внимание!
Если не разорвать связь с проектом, можно случайно отправить изменения в общий проект с шаблоном курсового проекта!
</strong></em>
![Рис. 1. Форк проекта](./docs/readme/img/fork-project.png)
Рис. 1. Создаем копию проекта
![Рис. 2. Продвинутые настройки](./docs/readme/img/advanced-settings.png)
Рис. 2. Переходим в продвинутые настройки репозитория
![Рис. 3. Разрыв связи](./docs/readme/img/unlink-fork.png)
Рис. 3. Разрываем связь в шаблонным проектом
![Рис. 4. Настройки участников проекта](./docs/readme/img/project-members.png)
Рис. 4. Настройки участников проекта
![Рис. 5. Добавить новых участников](./docs/readme/img/invite-member.png)
Рис. 5. Добавить новых участников
![Рис. 6. Добавление тьютора с ролью Maintainer](./docs/readme/img/make-tutor-a-maintainer.png)
Рис. 6. Добавление тьютора с ролью Maintainer
## Выполнение домашнего задания:
1. В своём форке проекта необходимо создать ветку от master под выполняемое задание. Ветку **необходимо (MUST)** назвать
hw-N, где N номер модуля, к которому относится выполняемое задание;
2. Выполнить задание;
3. Создать мерж-реквест ветки с решением в master в своём форке проекта;
4. Уведомить тьютора об отправке решения на проверку и поделиться ссылкой на мерж-реквест в Telegram;
5. После проверки задания тьютором он может оставить комментарии к решению. Если требующие исправления замечания
отсутствуют, тьютор засчитывает решение, оставляя отметку (approve) на мерж-реквесте. По итогам проверки тьютор
проставляет оценку за работу в таблице прогресса;
6. Необходимо устранить все обязательные замечания и добиться успешного прохождения проверки тьютором;
7. После того как решение зачтено тьютором, и работа над ним со стороны студента завершена, решение необходимо вмержить
в ветку master.
## Формат названий на курсе Go на примере домашнего задания №1 (HW1):
| Формат наименования | Пример |
|--------------------|------------------------------|
| Для ветки | hw-1 |
| Для коммита | [hw-1] Свободный комментарий |
| Для мерж-реквеста | [hw-1] Свободный комментарий |
## Прохождение автоматизированных проверок
На текущем потоке мы в пилотном режиме запускаем систему автоматизированной проверки решений. Это не означает, что
тьюторы будут проверять решения менее тщательно, напротив– мы хотим освободить тьюторов от рутинных проверок и
помочь им фокусироваться на проверке других важных аспектов реализации. Это требует от вас внимательнее относится
к именованию веток, потому что для запуска проверок необходимо чтобы ветки удовлетворяли указанному шаблону `hw-N`.
Поскольку это пилотный запуск тестирующей системы, возможно возникновение проблем в ее работе, в том числе ложно
негативных срабатываний, **успешное прохождения решением всех автоматизированных проверок не является обязательным**.
Тем не менее постарайтесь, чтобы ваше решение проходило столько проверок, на сколько это возможно. Уделите внимание
проверкам кода (линтеру golangci-lint). Все это поможет избежать лишних замечаний в мерж-реквестах, которые непременно
оставит тьютор, и позволит сдать задание быстрее и за меньшее количество проверок.
Блюдите культуру и гигиену работы с git, постарайтесь не пушить бессодержательные коммиты в систему контроля версий.
**Количество коммитов не оценивается**. Большое количество коммитов вызывает запуск автоматизированных проверок, а
ввиду ограниченности ресурсов это может создать очередь в их прохождении. Более того, большое количество коммитов в
репозитории, где одновременно работает много разработчиков (как обычно и бывает на настоящем крупном проекте), может
затруднить слияние и разрешение конфликтов, сложнее понять состояние репозитория и ориентироваться в истории. Хорошей
практикой считается выполнение объединения коммитов в один (squash) перед созданием мерж-реквеста и аналогичное
объединение коммитов с исправлениями в один перед повторной отправкой тьютору на повторную. Таким образом количество
коммитов в ветке будет соответствовать количеству итераций проверки. Мы не считаем количество коммитов и не оцениваем
работу по этому признаку. Сказанное выше является рекомендацией, но не требованием.
## Чтение файла конфигурации
В вашем решинии каждый из сервисов должен (MUST) использовать переменную окружения `CONFIG_FILE` в которой указан ПУТЬ
до файла конфигурации.
[Пример](cart/configs/values_ci.yaml) такого файла для сервиса `cart`, который используется в CI/CD пайплайне
(НЕ МОДИФИЦИРОВАТЬ).
Файлы конфигурации для локального запуска так-же [находятся в репозитории](cart/configs/values_local.yaml).
## Troubleshooting
1. Чтобы запустить product-service локально требуется выполнить команду
```
docker login gitlab-registry.ozon.dev
```
логин и пароль такие-же, как для доступа к https://gitlab.ozon.dev/
2. Если при прохождении джобы с тестами вы получаете ошибку
```
ERROR: Job failed: failed to pull image "gitlab-registry.ozon.dev/go/...." with specified policies [always]: Error response from daemon: pull access denied for gitlab-registry.ozon.dev/go/...., repository does not exist or may require 'docker login': denied: requested access to the resource is denied
```
напишите об этом тьютору, чтобы он сделал необходимые настройки. После подтверждения от тьютора, что работы проведены - просто перезапустите пайплайн

8
cart/Makefile Normal file
View File

@@ -0,0 +1,8 @@
BINDIR=${CURDIR}/bin
PACKAGE=route256/cart
bindir:
mkdir -p ${BINDIR}
build: bindir
echo "build cart"

View File

@@ -0,0 +1,19 @@
service:
host: localhost
port: 8080
workers: 5
jaeger:
host: localhost
port: 6831
product_service:
host: product-service
port: 8082
token: testToken
limit: 10
burst: 10
loms_service:
host: localhost
port: 8083

View File

@@ -0,0 +1,19 @@
service:
host: localhost
port: 8080
workers: 5
jaeger:
host: localhost
port: 6831
product_service:
host: localhost
port: 8082
token: testToken
limit: 10
burst: 10
loms_service:
host: localhost
port: 8083

3
cart/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module route256/cart
go 1.23.1

12
comments/Makefile Normal file
View File

@@ -0,0 +1,12 @@
BINDIR=${CURDIR}/bin
PACKAGE=route256/comments
bindir:
mkdir -p ${BINDIR}
build: bindir
echo "build comments"
run-migrations:
echo "run migrations"

View File

@@ -0,0 +1,20 @@
app:
edit_interval: 1s
service:
host: localhost
grpc_port: 8085
http_port: 8086
db_shards:
- host: "postgres-comments-shard-1"
port: 5432
user: comments-user-1
password: comments-password-1
db_name: comments_db
- host: "postgres-comments-shard-2"
port: 5432
user: comments-user-2
password: comments-password-2
db_name: comments_db

View File

@@ -0,0 +1,20 @@
app:
edit_interval: 1s
service:
host: localhost
grpc_port: 8085
http_port: 8086
db_shards:
- host: localhost
port: 5434
user: comments-user-1
password: comments-password-1
db_name: comments_db
- host: localhost
port: 5435
user: comments-user-2
password: comments-password-2
db_name: comments_db

3
comments/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module route256/comments
go 1.23.1

8
go.work Normal file
View File

@@ -0,0 +1,8 @@
go 1.23.1
use (
./cart
./loms
./notifier
./comments
)

11
loms/Makefile Normal file
View File

@@ -0,0 +1,11 @@
BINDIR=${CURDIR}/bin
PACKAGE=route256/loms
bindir:
mkdir -p ${BINDIR}
build: bindir
echo "build loms"
run-migrations:
echo "run migrations"

View File

@@ -0,0 +1,28 @@
service:
host: localhost
grpc_port: 8083
http_port: 8084
jaeger:
host: localhost
port: 6831
db_master:
host: postgres-master
port: 5432
user: loms-user
password: loms-password
db_name: loms_db
db_replica:
host: postgres-replica
port: 5432
user: loms-user
password: loms-password
db_name: loms_db
kafka:
host: kafka
port: 29092
order_topic: loms.order-events
brokers: kafka:29092

View File

@@ -0,0 +1,28 @@
service:
host: localhost
grpc_port: 8083
http_port: 8084
jaeger:
host: localhost
port: 6831
db_master:
host: localhost
port: 5432
user: loms-user
password: loms-password
db_name: loms_db
db_replica:
host: localhost
port: 5433
user: loms-user
password: loms-password
db_name: loms_db
kafka:
host: localhost
port: 29092
order_topic: loms.order-events
brokers: localhost:9092

3
loms/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module route256/loms
go 1.23.1

13
make/build.mk Normal file
View File

@@ -0,0 +1,13 @@
.PHONY: build
cart-build:
cd cart && GOOS=linux GOARCH=amd64 make build
loms-build:
cd loms && GOOS=linux GOARCH=amd64 make build
notifier-build:
cd notifier && GOOS=linux GOARCH=amd64 make build
comments-build:
cd comments && GOOS=linux GOARCH=amd64 make build

43
make/lint.mk Normal file
View File

@@ -0,0 +1,43 @@
CURDIR=$(shell pwd)
BINDIR=${CURDIR}/bin
GOVER=$(shell go version | perl -nle '/(go\d\S+)/; print $$1;')
LINTVER=v1.60.3
LINTBIN=bin/golangci-lint
bindir:
mkdir -p ${BINDIR}
install-lint: bindir
test -f ${LINTBIN} || \
(GOBIN=${BINDIR} go install github.com/golangci/golangci-lint/cmd/golangci-lint@${LINTVER} && \
mv ${BINDIR}/golangci-lint ${LINTBIN})
define lint
@if [ -f "$(1)/go.mod" ]; then \
output=$$(${LINTBIN} --config=.golangci.yaml run $(1)/... 2>&1); \
exit_code=$$?; \
echo "$$output"; \
if [ $$exit_code -ne 0 ]; then \
if echo "$$output" | grep -q "no go files to analyze"; then \
exit 0; \
else \
exit $$exit_code; \
fi \
fi \
fi
endef
cart-lint:
$(call lint,cart)
loms-lint:
$(call lint,loms)
notifier-lint:
$(call lint,notifier)
comments-lint:
$(call lint,comments)

8
notifier/Makefile Normal file
View File

@@ -0,0 +1,8 @@
BINDIR=${CURDIR}/bin
PACKAGE=route256/notifier
bindir:
mkdir -p ${BINDIR}
build: bindir
echo "build notifier"

View File

@@ -0,0 +1,6 @@
kafka:
host: kafka
port: 29092
order_topic: loms.order-events
consumer_group_id: notifier-group
brokers: kafka:29092

View File

@@ -0,0 +1,6 @@
kafka:
host: localhost
port: 29092
order_topic: loms.order-events
consumer_group_id: notifier-group
brokers: localhost:29092

3
notifier/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module route256/notifier
go 1.23.1