Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
46ff830
реализовал json-маршаллинг и проверку типов
StasMerzlyakov Apr 9, 2024
43c2e06
рефаторинг приложения
StasMerzlyakov Apr 10, 2024
dcbd75f
реализовал auth; TODO - доделать тесты на auth
StasMerzlyakov Apr 10, 2024
cdf4db1
уточнил интерфейс
StasMerzlyakov Apr 11, 2024
48b53af
реализовал balance; TODO - покрыть тестами[C
StasMerzlyakov Apr 11, 2024
0b9b9c2
уточнил ошибки
StasMerzlyakov Apr 12, 2024
8dfdb33
покрыл тестами balance useCase
StasMerzlyakov Apr 12, 2024
bc6736c
реализовал order use-case; покрыл тестами
StasMerzlyakov Apr 12, 2024
aa2879f
наработки по БД
StasMerzlyakov Apr 15, 2024
443d5cc
тест с go testcontainers
StasMerzlyakov Apr 15, 2024
77532cc
добавил метод в тестовую заглушку
StasMerzlyakov Apr 15, 2024
abaacd6
наработки - начал реализовывать работу с заказами
StasMerzlyakov Apr 16, 2024
ca57d6a
убрал лишний метод
StasMerzlyakov Apr 16, 2024
9cd692f
поправил тесты
StasMerzlyakov Apr 17, 2024
72756ba
реализовал обновление статуса заказа и получение списка заказов
StasMerzlyakov Apr 17, 2024
80efbce
поправил adr
StasMerzlyakov Apr 17, 2024
bcb208d
наработки
StasMerzlyakov Apr 17, 2024
7ab7e4c
немного поотлаживал пул системы начислений
StasMerzlyakov Apr 18, 2024
07e313d
наработки
StasMerzlyakov Apr 18, 2024
1438d4a
наработки на balance
StasMerzlyakov Apr 18, 2024
7e9aba3
реализова функции работы с балансом; TODO - тест на новые методы + ре…
StasMerzlyakov Apr 19, 2024
9c4653a
убрал unique по userId из orderData (может быть много начислений у од…
StasMerzlyakov Apr 19, 2024
de50775
добавил поля
StasMerzlyakov Apr 21, 2024
5a36309
реализовал обновление баланса по начислениям; поднял тесты
StasMerzlyakov Apr 21, 2024
b523907
переименовал метод
StasMerzlyakov Apr 21, 2024
743e4a9
добавил mainLogger, добавил retriable-обертку
StasMerzlyakov Apr 24, 2024
7420844
инициализация хранилище теперь через mainLogger
StasMerzlyakov Apr 24, 2024
07aa9cb
переименовал функцию получения логгера из контекста
StasMerzlyakov Apr 24, 2024
d939122
добавил ответ
StasMerzlyakov Apr 24, 2024
d9c4b57
добавил adr по повторному обращению к портам
StasMerzlyakov Apr 24, 2024
5678f98
Реализовал мидлы. TODO http handler
StasMerzlyakov Apr 24, 2024
640c119
добавил проверку статики
StasMerzlyakov Apr 25, 2024
0bbed79
вернул назад
StasMerzlyakov Apr 25, 2024
9fba541
поправил use-case для удобства использования в хендлере
StasMerzlyakov Apr 25, 2024
fd042b1
добавил auth и order http хэндлеры
StasMerzlyakov Apr 25, 2024
f0f5b09
реализовал хэндлеры
StasMerzlyakov Apr 25, 2024
827c2c9
разделил адаптеры на in и out
StasMerzlyakov Apr 26, 2024
03e20c0
сборка сервера
StasMerzlyakov Apr 26, 2024
0b7b7ff
поднял сервис
StasMerzlyakov Apr 26, 2024
b7b0818
отлаживаюсь
StasMerzlyakov Apr 26, 2024
8289de0
немного поправил вывод в лог
StasMerzlyakov Apr 26, 2024
e017756
хочу запустить проверку статики
StasMerzlyakov Apr 26, 2024
f26f606
вернул как было
StasMerzlyakov Apr 26, 2024
43b996b
Merge branch 'master' into iter3
StasMerzlyakov Apr 26, 2024
4511795
поправил названия переменных и методов
StasMerzlyakov Apr 26, 2024
23478de
странно что использовался math/rand.
StasMerzlyakov Apr 26, 2024
1b1e754
добавил скрипт для запуска интеграционных тестов локально
StasMerzlyakov Apr 27, 2024
5599170
нашел ошибки, автотесты теперь работают
StasMerzlyakov May 1, 2024
6c94f5f
правки по замечаниям
StasMerzlyakov May 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# iter1 (12.04):
разработка domain + use_case

https://excalidraw.com/#json=MATixU1PqTw5AQ3arX8II,R-BbMPCb1beMa2y0s3FdwA

# iter2 (19.04):
database, ports, refresh process

# iter3 (26.04):
mw, build app
13 changes: 13 additions & 0 deletions Questions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Обсудить ADR

# Миграции базы данных
Какие типовые решения/библиотеки применяются? (ответ получен - TODO https://github.com/pressly/goose)









26 changes: 26 additions & 0 deletions adr/adr.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Номер (ADR-XYZ)
## Заголоовк
- Название ADR
- Статус [proposed (предложен), accepted (принят) и superseded (замещён)]
- Дата изменения статуса
- Описание принятого/предложенного решения

## Контекст
В документы должен быть описан контекст, почему принято именно такое решение. Контекст — довольно широкое понятие. Он включает в себя доменную область, пользовательские сценарии, используемые технологии и даже размер и опытность команды разработки.

## Тело
Следом идёт непосредственно «тело» решения. Тут есть один интересный момент: в книге предлагается использовать утвердительные предложения. Не размышления в духе «Я думаю, что лучше сделать вот так», а утверждения «Мы будем делать вот так». То есть все сомнения и мысли мы оставляем для комментариев, но после обсуждения и принятия уже не должно быть фраз с «Я думаю, что...».

## Причины принятия решения.
Здесь предлагается сфокусироваться на том, почему мы будем что-то делать, а не как мы будем это делать. Кстати, именно «почему», а не «как» является вторым важным вопросом архитектуры.

## Последствия.
Тут вступает в силу первый важный закон архитектуры: любое решение является компромиссом, у которого есть сильные и слабые стороны. В этом разделе стоит их расписать.

## Комплаенс (проверка соответствия).
Это раздел про то, как мы будем проверять, что решению следует. Про комплаенс можно написать отдельную статью, а то и не одну. В качестве примера: если принято решение о разделении кода сервисов на слои, то можно воспользоваться специальной автоматизированной тулой (например, ArchUnit или NetArchTest), которая сможет проверить, что код соответствует принятому решению.

## Заметки.
Тут указывается автор, дата принятия, кем принято. Чаще всего в обсуждении принимает участие более широкий круг разработчиков, но аппрувить могут только определённые люди. Это может быть вышестоящий архитектор или же архитектурное комьюнити.


33 changes: 33 additions & 0 deletions adr/adr_001_pgx_configuration_2024_04_15.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ADR_001

## Название
Настрока соединения с БД

## Статус
proposed

## Дата
2024-04-15

## Описание принятого/предложенного решения
На основе статьи [Как работать с Postgres в Go: практики, особенности, нюансы](https://habr.com/ru/companies/oleg-bunin/articles/461935/) настройка pgx v5 выглядит так:

```go
pConf.MaxConns = int32(...) // ограничение кол-ва соединений
pConf.ConnConfig.DefaultQueryExecMode = pgx.QueryExecModeSimpleProtocol // режим Simple Query
pConf.ConnConfig.RuntimeParams["standard_conforming_strings"] = "on"

```

[Протокол Simple Query](https://www.postgresql.org/docs/15/protocol-flow.html#id-1.10.6.7.4)


На основе статьи [Работаем с PostgreSQL в Go. Опыт Авито](https://habr.com/ru/companies/avito/articles/716516/) ещё добавил
```go
pConf.MaxConnLifetime = 5 * time.Minute
pConf.MaxConnIdleTime = 5 * time.Minute
```




47 changes: 47 additions & 0 deletions adr/adr_002_order_score_2024_04_16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ADR_002

## Название
Защита от обращений к сервису начислений с одним и тем же номером заказа при работе приложения в несколько инстансов

## Статус
proposed

## Дата
2024-04-16

## Описание принятого/предложенного решения
В таблицу order добавлено поле score, содержащее время для следующего обращения. При получении запросов, по которым необходимо обратиться к сервису начислений проверяется значение этого поля. Если поле меньше текущего времени данное поле увеличивается на delta.

```sql
-- таблица
create table if not exists orderData(
number varchar(255),
userId int not null,
status varchar(255),
accrual float8,
uploaded_at timestamptz,
score timestamptz not null default now(),
primary key(number),
unique (userId),
foreign key (userId) references userInfo(userId)
);
```

```sql
-- запрос на получение данных
update orderData set score = $1
where number in
(select number from orderdata where status = ANY($2) and score < $3 limit $4)
returning
number, userId, status, accrual, uploaded_at;
```


## Недостатки решения
- 2023-04-17 рост размера БД при обновлении score

## Комментарии
### 2023-04-17
- можно попробовать вынести score в отдельную таблицу c tablespace в оперативке; но надо будет сделать аккуратный select с left outer join на случай, если грохнется tablespace
- интересно - как происходит репликация таблиц из tablespace, размещенном в оперативке

37 changes: 37 additions & 0 deletions adr/adr_003_order_pool_process_2024_04_18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ADR_003

## Название
Описание процесса пула системы начислений

## Статус
proposed

## Дата
2024-04-18

## Описание принятого/предложенного решения
### Процесс пула системы начислений
Статусная модель:
- при регистрации номера статус у номер domain.OrderStatusNew
- при получении от системы начислений бонусов на данный номер:
domain.AccrualStatusInvalid -> domain.OrderStratusInvalid
domain.AccrualStatusProcessed -> domain.OrderStatusProcessing + сохраняются данные о начислении

Пулинг системы начислений запускается вызовом order.PoolAcrualSystem.
order.PoolAcrualSystem
- запускает горутины:
- пула системы начислений в количестве config.AcrualSystemPoolCount
- обновления статусов начислений (1 штука), обновляющая статусы либо по config.BatchSize штук(по дефолту 10) либо через 2 секунды
- получение заказов в статусе domain.OrderStatusNew

При возникновении ошибки все горутины приостанавливают работу на 5 секунд.
Остановка горутин по остановке контекста.
Контекс должен содержать logger.

Функции реализованы по мотивам [Advanced Go Concurrency Patterns](https://go.dev/blog/io2013-talk-concurrency)

## Недостатки решения


## Комментарии

38 changes: 38 additions & 0 deletions adr/adr_004_balance_score_2024_04_18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ADR_004

## Название
Обеспечение защиты от некорректного обновления баланса при работе в несколько потоков(например, при обработке запроса на списание и пуле системы начисления заказов)

## Статус
proposed

## Дата
2024-04-18

## Описание принятого/предложенного решения
```sql
-- таблица
create table if not exists balance(
balanceId serial,
userId int not null,
current float8 not null default 0,
withdrawn float8 not null default 0,
release int not null default 0,
primary key(balanceId),
unique (userId),
foreign key (userId) references userInfo(userId)
);
```
В таблицу balance добавлено поле release. При обновлении баланса
```sql
update balancer set current=$1,withdrawn=$2,release=release+1 where userId=$3 and release=$3 returning balanceId
```
если при обновлении не было обновлено ни одной записи (pgx.ErrNoRows) - значит баланс уже был обновлен кем-то другим.
Необходимо перечитать текущие значения баланса.


## Недостатки решения


## Комментарии

34 changes: 34 additions & 0 deletions adr/adr_005_balance_select_test_infser_2024_04_19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ADR_005

## Название
Проверка наличия и, при необходимости, создание записи о балансе при получении баланса

## Статус
proposed

## Дата
2024-04-19

## Контекст
При получании баланса записей для пользователя таких записей может и не быть. Хочется сделать так, что после вызова функции получения баланса запись точно была создана. Можно добавить создание записи с нулевым балансом в функцию регистрации пользователя, но, в случае развития проекта(например будут ещё какие-то подсистемы) придется каждый раз добавлять инициализацию данных для этих подсистем в метод регистарции пользователя - что будет сложно поддерживать и покрывать тестами.

## Описание принятого/предложенного решения
Основываясь на статье [Write a Postgres Get or Create SQL Query](https://stackoverflow.com/questions/16123944/write-a-postgres-get-or-create-sql-query) sql для получения баланса выглядит так:


```sql
-- запрос на получение пользователя
with ins as (
insert into balance(userId) values (1) on conflict (userId) do nothing returning *
)
select * from ins
union
select * from balance
where userId=1;
```

## Недостатки решения


## Комментарии

27 changes: 27 additions & 0 deletions adr/adr_006_balance_update_transaction_2024_04_19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ADR_006

## Название
Обеспечение транзакционности операций с обновлением баланса

## Статус
proposed

## Дата
2024-04-19

## Контекст
С учетом релизной системы учета обновлений баланса, необходимо обеспечить атомарность операций корерктировки баланса с добавления записи о списании
и корректировки баласа с обновлением данных от системы расчета начислений.

## Описание принятого/предложенного решения
В методе обновления баланса (storage.UpdateBalanceByWithdraw) в транзакции происходит добавление записи о списании и обновление записи о балансе. Если update баланса ничего не вернул - транзакция откатывается.

Аналогичный прием в методе storage.UpdateBalanceByOrder

## Недостатки решения

## Связана
ADR_004, ADR_005

## Комментарии

75 changes: 75 additions & 0 deletions adr/adr_007_database_structure_2024_04_19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# ADR_007

## Название
Структура табилц в БД

## Статус
proposed

## Дата
2024-04-19

## Описание принятого/предложенного решения
[PlantUML в Visual Studio Code](https://logrocon.ru/news/plantuml_visualstudiocode)

Запустить prview в linux - Alt-D.

```plantuml
@startuml
class userInfo{
userId serial
login text not null
hash text not null
salt text not null
primary key(userId)
unique (login)
}
class balance {
balanceId serial
userId int not null
current float8 not null default 0
withdrawn float8 not null default 0
release int not null default 0
primary key(balanceId)
unique (userId)
foreign key (userId) references userInfo(userId)
}

userInfo "1..1" <- balance

class orderData {
number varchar(255)
userId int not null
status varchar(255)
accrual float8
uploaded_at timestamptz
score timestamptz not null
primary key(number)
foreign key (userId) references userInfo(userId)
}

userInfo "1..N" <- orderData

class withdrawal {
withdrawalId serial
balanceId int not null
number varchar(255) not null
sum float8 not null
processed_at timestamptz not null default now()
primary key(withdrawalId)
foreign key (balanceId) references balance(balanceId)
}

balance "1..N" <- withdrawal

@enduml

```


## Недостатки решения

## Связана
ADR_004, ADR_005

## Комментарии
36 changes: 36 additions & 0 deletions adr/adr_008_balance_update_by_order_process_2024_04_21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# ADR_008

## Название
Описание процесса обновления баланса по начислениям

## Статус
proposed

## Дата
2024-04-21

## Описание принятого/предложенного решения
### Процесс пула системы начислений
Статусная модель:
- при полученни данных о начислении статус у номера domain.OrderStatusProcessing
- после обновления баланса статус изменяется на domain.OrderStatusProcessed

Обновление баланса запускается вызовом balance.PoolOrders
balance.PoolOrders
- запускает горутины:
- обновления баланса
- получение заказов в статусе domain.OrderStatusProcessing

При возникновении ошибки все горутины приостанавливают работу на 5 секунд.
Остановка горутин по остановке контекста.
Контекс должен содержать logger.

Функции реализованы по мотивам [Advanced Go Concurrency Patterns](https://go.dev/blog/io2013-talk-concurrency)

## Недостатки решения


## Комментарии

## Связана
ADR_003
Loading