Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
335 changes: 335 additions & 0 deletions students/Tsuytskou_Kiryl/lab_01/README.md

Large diffs are not rendered by default.

401 changes: 401 additions & 0 deletions students/Tsuytskou_Kiryl/lab_01/analysis.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
183 changes: 183 additions & 0 deletions students/Tsuytskou_Kiryl/lab_01/diagrams/sequence-error-payment.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
@startuml
title Сценарий с ошибкой: Таймаут ML-модератора (Anti-spam API недоступен)

actor "Продавец" as Seller
participant "Web UI" as UI
participant "API Gateway" as Gateway
participant "Ad Service" as AdSvc
participant "Image Store\n(S3/MinIO)" as ImgStore
database "PostgreSQL" as DB
participant "ML Moderator\n(Anti-spam API)" as ML
queue "Event Bus\n(RabbitMQ)" as Bus
participant "Moderation Retry\nWorker" as RetryWorker
participant "Notification\nService" as Notify

note over Seller, Notify
Шаг 1: Пользователь заполнил форму объявления
и нажал "Опубликовать"
end note

== Транзакция №1: Загрузка фото и сохранение объявления ==

Seller -> UI: Заполняет форму\n(категория, заголовок, цена, описание, 3 фото)
UI -> UI: Валидация на фронте

Seller -> UI: Нажать "Опубликовать"
UI -> Gateway: POST /api/ads\nmultipart/form-data
activate Gateway

Gateway -> Gateway: Аутентификация\nи верификация пользователя
Gateway -> AdSvc: Пересылка запроса
activate AdSvc

AdSvc -> AdSvc: Валидация данных\n(цена > 0, заголовок не пуст,\nкатегория существует)

== Параллельная загрузка изображений ==

AdSvc -> ImgStore: upload_image(file1, file2, file3)
activate ImgStore
ImgStore --> AdSvc: [url1, url2, url3]
deactivate ImgStore

note over AdSvc
Фото успешно загружены
Теперь нужно проверить текст через ML-модератора
end note

== Шаг 2: Ошибка при обращении к ML-модератору ==

AdSvc -> ML: checkContent(title, description, category)
activate ML

note over ML #FFAAAA
⚠️ ML-модератор НЕ ДОСТУПЕН
Timeout 3 секунды / 503 Service Unavailable
end note

ML --x AdSvc: TimeoutException / HTTP 503
deactivate ML

AdSvc -> AdSvc: Перехват исключения

note over AdSvc
Система НЕ откатывает транзакцию
Фото уже загружены
Объявление будет сохранено со статусом PENDING_MODERATION
end note

AdSvc -> DB: BEGIN TRANSACTION
activate DB

AdSvc -> DB: INSERT INTO ads\n(id, seller_id, title, price,\n category, description, images,\n status, created_at)\nVALUES ('A-2026-0142', ...)\nstatus = 'PENDING_MODERATION'
DB --> AdSvc: OK

AdSvc -> DB: INSERT INTO moderation_queue\n(ad_id, reason, priority, created_at)\nVALUES ('A-2026-0142',\n 'ML_TIMEOUT', 'HIGH', NOW())
DB --> AdSvc: OK

AdSvc -> DB: INSERT INTO outbox\n(event_type='AdPendingModeration',\n payload=..., status='pending')
DB --> AdSvc: OK

AdSvc -> DB: COMMIT TRANSACTION
DB --> AdSvc: Committed
deactivate DB

AdSvc -> Bus: publish(AdPendingModeration,\nad_id='A-2026-0142',\nreason='ML_TIMEOUT')
activate Bus
Bus --> AdSvc: ACK
deactivate Bus

note right of AdSvc #FFFFAA
Объявление в статусе PENDING_MODERATION
Задача в очереди для повторной проверки модератором
end note

AdSvc --> Gateway: 202 Accepted\n{ad_id: "A-2026-0142",\nstatus: "PENDING_MODERATION",\nmessage: "Проверка антисписком задерживается. Объявление появится автоматически"}
deactivate AdSvc

Gateway --> UI: 202 Accepted\n{ad_id, status, message}
deactivate Gateway

UI --> Seller: Показать уведомление:\n"Объявление отправлено на проверку. Обычно это занимает 5 минут"

note over Seller
Продавец получил предупреждение
Объявление сохранено, но пока не видно другим пользователям
end note

== Асинхронная обработка ошибки (Retry через 30 секунд) ==

Bus -> RetryWorker: consume(AdPendingModeration)
activate RetryWorker

RetryWorker -> RetryWorker: Задержка 30 секунд\n(первая попытка retry к ML)

... 30 секунд спустя ...

RetryWorker -> ML: checkContent(title, description, category)
activate ML

note over ML #AAFFAA
✅ ML-модератор снова доступен
Успешная проверка текста
end note

ML --> RetryWorker: verdict = "CLEAN"\nconfidence = 0.96\nreason = NULL
deactivate ML

RetryWorker -> DB: BEGIN TRANSACTION
activate DB

RetryWorker -> DB: UPDATE ads\nSET status='ACTIVE',\nmoderation_verdict='CLEAN',\nmoderated_at=NOW()\nWHERE id='A-2026-0142'
DB --> RetryWorker: OK

RetryWorker -> DB: UPDATE moderation_queue\nSET status='PROCESSED',\nresolved_at=NOW()\nWHERE ad_id='A-2026-0142'
DB --> RetryWorker: OK

RetryWorker -> DB: INSERT INTO search_index_queue\n(ad_id, action, queued_at)\nVALUES ('A-2026-0142', 'INDEX', NOW())
DB --> RetryWorker: OK

RetryWorker -> DB: UPDATE outbox\nSET status='sent'\nWHERE event_type='AdPendingModeration'\nAND payload->>'ad_id'='A-2026-0142'
DB --> RetryWorker: OK

RetryWorker -> DB: COMMIT TRANSACTION
deactivate DB

RetryWorker -> Bus: publish(AdPublished,\nad_id='A-2026-0142',\nseller_id='USER-123')
activate Bus
Bus --> RetryWorker: ACK
deactivate Bus

note over RetryWorker #AAFFAA
Объявление успешно проверено
Теперь активно и доступно в поиске
end note

deactivate RetryWorker

== Асинхронная отправка уведомлений продавцу ==

Bus -> NotificationWorker: consume(AdPublished)
activate NotificationWorker

NotificationWorker -> NotificationWorker: Получить данные продавца\n(email, телефон) по seller_id

NotificationWorker -> Notify: sendEmail(to="seller@example.com",\ntemplate="ad_published",\ndata={ad_id: "A-2026-0142",\ntitle: "iPhone 13",\nurl: "/ads/A-2026-0142"})
activate Notify

Notify -> Notify: Формирование и отправка\nписьма через Email-провайдера
Notify --> NotificationWorker: Status: sent\nMessage-ID: msg-789
deactivate Notify

NotificationWorker -> DB: INSERT INTO notification_log\n(ad_id, recipient, type, status, sent_at)\nVALUES ('A-2026-0142',\n'seller@example.com', 'email', 'delivered', NOW())
activate DB
DB --> NotificationWorker: OK
deactivate DB

note over NotificationWorker #AAFFAA
Email успешно отправлен продавцу
Продавец знает, что объявление опубликовано
end note

deactivate NotificationWorker

@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions students/Tsuytskou_Kiryl/lab_01/diagrams/sequence-happy.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
@startuml
title Успешный сценарий: Публикация объявления

actor "Продавец" as Seller
participant "Web UI" as UI
participant "API Gateway" as Gateway
participant "Ad Service" as AdSvc
participant "ML Moderator" as ML
participant "Image Store\n(S3/MinIO)" as ImgStore
database "PostgreSQL" as DB
queue "Event Bus\n(RabbitMQ)" as Bus
participant "Search Worker" as SearchWorker
participant "Notification\nWorker" as NotifyWorker
participant "Email/Push\nService" as Notify

== Транзакция №1: Создание объявления ==

Seller -> UI: Заполняет форму объявления\n(категория, заголовок, цена, описание)
activate UI

UI -> UI: Валидация на фронте\n(цена > 0, заголовок не пуст)

Seller -> UI: Выбирает 3 фото для загрузки
UI -> UI: Сжимает фото перед отправкой

UI -> Gateway: POST /api/ads\nmultipart/form-data\n{title: "iPhone 13",\nprice: 45000,\ncategory: "Электроника",\nimages: [file1, file2, file3]}
activate Gateway

Gateway -> Gateway: Аутентификация\nи верификация пользователя
Gateway -> AdSvc: Пересылка запроса
activate AdSvc

AdSvc -> AdSvc: Валидация данных\n(цена, категория, длина заголовка)

== Параллельная загрузка изображений ==

AdSvc -> ImgStore: upload_image(file1)
activate ImgStore
ImgStore --> AdSvc: https://cdn.ads.by/img/abc123.jpg
deactivate ImgStore

AdSvc -> ImgStore: upload_image(file2)
activate ImgStore
ImgStore --> AdSvc: https://cdn.ads.by/img/def456.jpg
deactivate ImgStore

AdSvc -> ImgStore: upload_image(file3)
activate ImgStore
ImgStore --> AdSvc: https://cdn.ads.by/img/ghi789.jpg
deactivate ImgStore

== Синхронная модерация (ML) ==

AdSvc -> ML: checkContent(title, description,\ncategory)
activate ML
ML -> ML: Анализ на спам,\nзапрещённые слова,\nмошенничество
ML --> AdSvc: verdict = "CLEAN"\nconfidence = 0.97
deactivate ML

AdSvc -> DB: BEGIN TRANSACTION
activate DB

AdSvc -> DB: INSERT INTO ads\n(id, seller_id, title, price,\n category, description, status,\n images, created_at)\nVALUES ('A-2026-0142', ...)\nstatus = 'ACTIVE'
DB --> AdSvc: OK

AdSvc -> DB: INSERT INTO search_index_queue\n(ad_id, action, queued_at)\nVALUES ('A-2026-0142', 'INDEX', NOW())
DB --> AdSvc: OK

AdSvc -> DB: INSERT INTO outbox\n(event_type='AdPublished',\n payload=..., status='pending')
DB --> AdSvc: OK

AdSvc -> DB: COMMIT TRANSACTION
DB --> AdSvc: Committed
deactivate DB

AdSvc --> Gateway: 201 Created\n{ad_id: "A-2026-0142",\nstatus: "ACTIVE",\nurl: "/ads/A-2026-0142"}
deactivate AdSvc

Gateway --> UI: 201 Created\n{ad_id, status, url}
deactivate Gateway

UI --> Seller: Показывает карточку\n"Объявление опубликовано!"
deactivate UI

== Асинхронная индексация в поиске ==

Bus -> SearchWorker: consume(AdPublished)
activate SearchWorker

SearchWorker -> SearchWorker: Формирование\nElasticsearch документа

SearchWorker -> SearchWorker: Индексация\n(шард по категории)

SearchWorker -> DB: UPDATE outbox\nSET status='sent'\nWHERE event_type='AdPublished'
activate DB
DB --> SearchWorker: OK
deactivate DB

deactivate SearchWorker

== Асинхронная отправка уведомлений ==

Bus -> NotifyWorker: consume(AdPublished)
activate NotifyWorker

NotifyWorker -> NotifyWorker: Определение каналов\n(email для продавца)

NotifyWorker -> Notify: sendEmail(seller@email.com,\n"Ваше объявление A-2026-0142 опубликовано!")
activate Notify
Notify --> NotifyWorker: Message-ID: msg-456\nStatus: queued
deactivate Notify

NotifyWorker -> DB: INSERT INTO notification_log\n(ad_id, recipient, type, status)\nVALUES ('A-2026-0142', ...)
activate DB
DB --> NotifyWorker: OK
deactivate DB

deactivate NotifyWorker

@enduml
Loading
Loading