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
39 changes: 39 additions & 0 deletions students/Mihnovec_Stas/lab-01/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Анализ границ ответственности и обработка исключений

## Транзакционные границы
Транзакция начинается в момент получения API-запроса от пользователя на создание жалобы. Она включает в себя проверку существования новости, проверку на дубликаты (идемпотентность) и запись в БД. Вызов внешнего сервиса модерации вынесен за рамки строгой БД-транзакции во избежание блокировок при таймаутах.

| Операция | Тип (Sync/Async) | Откат при ошибке | Стратегия повтора (Retry) | Идемпотентность |
|----------|------------------|------------------|---------------------------|-----------------|
| Сохранение жалобы в БД | Синхронная | Да (БД транзакция ROLLBACK) | Нет | Да (Ключ: `user_id` + `news_id`) |
| Проверка через AI Moderation | Синхронная (с коротким таймаутом) | Нет (Переход в Async) | Отправка в очередь RabbitMQ с экспоненциальной задержкой | Да (Сервис ИИ кэширует хеш текста) |
| Уведомление модераторов (Email) | Асинхронная | Нет (best-effort) | 3 попытки (через брокер сообщений) | Да (дедупликация по `complaint_id`) |
| Скрытие новости (если 100% фейк)| Асинхронная | Нет | Retry до победного (Dead Letter Queue) | Да (Проверка текущего статуса новости) |

---

## Обработка исключительных ситуаций

### 1. Исключительная ситуация: Таймаут сервиса Автомодерации (AI Checker)

**Условие**: Внешний сервис HTTP POST `/analyze` не отвечает более 3 секунд.
**Обнаружение**: HTTP-клиент (например, Axios или HttpClient) выбрасывает `TimeoutException`.
**Реакция**:
1. Система не прерывает процесс создания жалобы.
2. Жалоба фиксируется в БД со статусом `PENDING` (Ожидает обработки).
3. Событие отправляется в очередь (RabbitMQ/Kafka) для фоновой обработки.
**Компенсация**: Компенсация не требуется, так как транзакция в БД успешна. Задача будет выполнена позже воркером.
**Уведомление пользователя**: "Жалоба принята. Из-за высокой нагрузки проверка займет чуть больше времени."

### 2. Исключительная ситуация: Нарушение уникальности (Race Condition / Double Click)

**Условие**: Пользователь дважды нажимает кнопку "Отправить", генерируя два одновременных запроса.
**Обнаружение**: База данных выбрасывает `UniqueConstraintViolationException` (уникальный индекс на `user_id` + `news_id`).
**Реакция**:
1. Первый запрос проходит успешно.
2. Второй запрос перехватывает ошибку уникальности.
**Компенсация**: Откат транзакции второго запроса.
**Уведомление пользователя**: "Ваша жалоба уже была принята ранее." (возвращается успешный ответ, чтобы не пугать пользователя ошибкой 500).

### 3. Бонус: Реализация паттерна Circuit Breaker
Для защиты системы от каскадных сбоев, если сервис AI-модерации лежит полностью (ошибки 5xx подряд), система открывает Circuit Breaker. Запросы перестают отправляться во внешний сервис и **сразу** складываются в RabbitMQ, что экономит 3 секунды ожидания таймаута на каждом запросе пользователя, сохраняя отзывчивость UI.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions students/Mihnovec_Stas/lab-01/diagrams/sequence-error.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@startuml
skinparam maxMessageSize 150
actor "Читатель" as User
participant "Web UI" as UI
participant "Complaint Service" as CompAPI
database "PostgreSQL" as DB
participant "AI Moderation" as Moderation
participant "RabbitMQ (Broker)" as Broker

User -> UI: Нажать "Отправить жалобу"
UI -> CompAPI: POST /api/complaints
activate CompAPI

CompAPI -> DB: INSERT complaint (status: PENDING)
DB --> CompAPI: complaint_id

CompAPI -> Moderation: POST /analyze {text}
activate Moderation
Moderation --x CompAPI: TimeoutException (3000ms)
deactivate Moderation

note over CompAPI: Перехват ошибки.\nПереход в fallback режим.

CompAPI -> Broker: Publish Event: ModerationRetryQueue {complaint_id}
activate Broker
Broker --> CompAPI: ACK
deactivate Broker

note over DB: Статус остается PENDING

CompAPI --> UI: 202 Accepted, "Принято в обработку с задержкой"
deactivate CompAPI

UI --> User: Показать: "Жалоба сохранена, проверяем..."
@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions students/Mihnovec_Stas/lab-01/diagrams/sequence-happy.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@startuml
skinparam maxMessageSize 150
actor "Читатель" as User
participant "Web UI" as UI
participant "API Gateway" as API
participant "Complaint Service" as CompAPI
database "PostgreSQL" as DB
participant "AI Moderation" as Moderation
participant "RabbitMQ (Broker)" as Broker

User -> UI: Нажать "Отправить жалобу"
UI -> API: POST /api/complaints\n{news_id, reason}
activate API

API -> CompAPI: CreateComplaint()
activate CompAPI

CompAPI -> DB: Проверка дубликатов (user_id, news_id)
DB --> CompAPI: Not found (OK)

CompAPI -> DB: INSERT complaint (status: PENDING)
DB --> CompAPI: complaint_id

CompAPI -> Moderation: POST /analyze {text}
activate Moderation
Moderation --> CompAPI: status: REQUIRES_REVIEW
deactivate Moderation

CompAPI -> DB: UPDATE status (REVIEW_PENDING)

CompAPI -> Broker: Publish Event: ComplaintCreated
activate Broker
Broker --> CompAPI: ACK
deactivate Broker

CompAPI --> API: 201 Created, complaint_id
deactivate CompAPI

API --> UI: Успешный ответ
deactivate API
UI --> User: Показать уведомление "Жалоба принята"
@enduml
37 changes: 37 additions & 0 deletions students/Mihnovec_Stas/lab-01/scenarios.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Feature: Подача жалобы на фейковую новость

Scenario: Успешная подача жалобы на новость
Given пользователь авторизован как "reader@example.com"
And новость "Инопланетяне приземлились" с ID "NEWS-123" существует
When пользователь отправляет жалобу на "NEWS-123" с причиной "Недостоверный источник"
And сервис авто-модерации работает корректно
Then система создает жалобу со статусом "REVIEW_PENDING"
And система публикует событие "ComplaintCreated" в брокер сообщений
And пользователь видит сообщение "Ваша жалоба отправлена на проверку модераторам"

Scenario: Ошибка - Новость уже удалена (Not Found)
Given пользователь авторизован как "reader@example.com"
And новость с ID "NEWS-999" была удалена автором минуту назад
When пользователь отправляет жалобу на "NEWS-999"
Then система возвращает ошибку 404 "Новость не найдена"
And жалоба НЕ сохраняется в базу данных
And пользователь видит сообщение "Эта новость уже удалена"

Scenario: Таймаут сервиса AI-модерации (Fallback)
Given пользователь авторизован как "reader@example.com"
And новость "Секретный заговор" с ID "NEWS-456" существует
When пользователь отправляет жалобу на "NEWS-456"
And сервис авто-модерации не отвечает в течение 3 секунд
Then система сохраняет жалобу со статусом "PENDING"
And система ставит задачу в очередь "ModerationRetryQueue"
And пользователь видит сообщение "Жалоба принята. Из-за высокой нагрузки проверка займет чуть больше времени."

Scenario: Идемпотентность - Защита от двойного клика (Дубликат)
Given пользователь авторизован как "reader@example.com"
And новость "Шок контент" с ID "NEWS-777" существует
And пользователь уже подавал жалобу на "NEWS-777" 5 минут назад
When пользователь повторно отправляет жалобу на "NEWS-777"
Then система обнаруживает дубликат по ключу "reader@example.com:NEWS-777"
And система НЕ создает новую запись в БД
And система возвращает статус успешного выполнения
And пользователь видит сообщение "Вы уже пожаловались на эту новость ранее"
43 changes: 43 additions & 0 deletions students/Mihnovec_Stas/lab-01/use-case.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## Use-case: Подача жалобы на фейковую новость

**Первичный актор**: Авторизованный читатель

**Цель**: Сообщить о недостоверной информации в новости для её последующей проверки и возможной блокировки.

**Предусловия**:
- Пользователь авторизован в системе.
- Статья (новость) существует в системе и доступна для чтения.
- Пользователь ранее не подавал жалобу на эту же новость (проверка идемпотентности).

**Основной поток** (Happy Path):
1. Пользователь нажимает кнопку "Пожаловаться на фейк" на странице новости.
2. Система запрашивает причину (например, "Недостоверный источник", "Сгенерировано ИИ", "Кликбейт").
3. Пользователь выбирает причину и нажимает "Отправить".
4. Система (UI) отправляет API-запрос на создание жалобы.
5. Сервис жалоб сохраняет запись в БД со статусом "PENDING".
6. Сервис жалоб синхронно отправляет текст новости во внешний сервис Автомодерации (AI Checker).
7. Сервис Автомодерации возвращает статус "REQUIRES_HUMAN_REVIEW" (требуется ручная проверка).
8. Сервис жалоб обновляет статус жалобы в БД.
9. Система ставит задачу в очередь на асинхронную отправку email-уведомления модераторам.
10. Система возвращает пользователю сообщение об успешной отправке жалобы.

**Постусловия**:
- Жалоба зафиксирована в БД.
- Новость получает пометку (внутреннюю) о наличии активной жалобы.
- Модераторы уведомлены.

**Альтернативные потоки**:
- 7a. Сервис Автомодерации уверенно определяет 100% фейк (возвращает "FAKE_CONFIRMED").
- 7a1. Сервис жалоб автоматически скрывает новость из Ленты.
- 7a2. Автору новости отправляется предупреждение.
- 7a3. Возврат к шагу 10.

**Исключительные ситуации**:
- 6a. Сервис Автомодерации недоступен (Timeout).
- 6a1. Система ловит ошибку таймаута.
- 6a2. Жалоба остается в БД со статусом "PENDING".
- 6a3. Задача на проверку ставится в брокер сообщений (асинхронный retry).
- 6a4. Пользователь получает ответ: "Жалоба принята и ожидает проверки".
- 4a. Пользователь отправляет повторную жалобу на ту же новость (Double click).
- 4a1. Срабатывает проверка ключа идемпотентности (user_id + news_id).
- 4a2. Система возвращает статус 200 OK и ID уже существующей жалобы без дублирования в БД.
Loading
Loading