Initial commit: VoIdeaAI - voice-first AI idea assistant

This commit is contained in:
2026-05-13 12:51:42 +03:00
commit 688d043dad
421 changed files with 47915 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
# Обработка ошибок
## Матрица ошибок по слоям
| Слой | Что делаем | Пример |
|------|-----------|--------|
| **API** | HTTPException с detail и status_code | `raise HTTPException(404, detail="Not found")` |
| **Services** | Бизнес-исключения без HTTP-статусов | `raise IdeaNotFoundError(idea_id)` |
| **Integrations** | try/except с fallback | `return AIResult(success=False, error=...)` |
| **Data/DB** | Ошибки не всплывают выше | Ловим в сервисе |
---
## Иерархия исключений
```python
# app/core/exceptions.py
class AppError(Exception):
"""Базовое исключение приложения."""
def __init__(self, message: str, details: dict | None = None):
self.message = message
self.details = details or {}
class NotFoundError(AppError):
"""Ресурс не найден."""
def __init__(self, resource: str, resource_id: str):
super().__init__(f"{resource} not found: {resource_id}", {"resource": resource, "id": resource_id})
class ValidationError(AppError):
"""Ошибка валидации."""
def __init__(self, field: str, message: str):
super().__init__(message, {"field": field})
class AuthError(AppError):
"""Ошибка аутентификации."""
def __init__(self, message: str = "Authentication failed"):
super().__init__(message)
class ForbiddenError(AppError):
"""Нет прав."""
def __init__(self, message: str = "Access denied"):
super().__init__(message)
```
---
## Fallback Pattern (для внешних вызовов)
```python
# Паттерн для всех вызовов внешних API
async def call_with_fallback(provider: AIProvider, prompt: str) -> AIResult:
max_retries = 2
last_error = None
for attempt in range(max_retries + 1):
try:
result = await asyncio.wait_for(
provider.analyze(prompt),
timeout=10.0
)
if result.success:
return result
last_error = result
except asyncio.TimeoutError:
last_error = AIResult(success=False, error="Timeout")
except Exception as e:
last_error = AIResult(success=False, error=str(e))
if attempt < max_retries:
await asyncio.sleep(2 if attempt == 0 else 5)
return last_error
```
---
## Логирование ошибок
| Уровень | Когда | Пример |
|---------|-------|--------|
| DEBUG | Входящие параметры | `Request params: id=123` |
| INFO | Успешная операция | `User created: id=456` |
| WARNING | Timeout, retry | `Yandex GPT timeout, retry 1/2` |
| ERROR | Ошибка внешнего API | `GigaChat 500: Internal error` |
| CRITICAL | Исчерпаны все retry | `All AI providers failed for idea 789` |
---
## Graceful Degradation
Когда внешний сервис недоступен:
1. **DB недоступна** → 503 Service Unavailable
2. **Redis недоступен** → работаем без кэша (log WARNING)
3. **AI провайдер недоступен** → возвращаем fallback результат
4. **Celery недоступен** → выполняем задачу синхронно
---
## [ASK] Вопросы по обработке ошибок
- Нужны ли пользовательские исключения для всех бизнес-сценариев?
- Нужен ли sentry или аналогичный мониторинг ошибок?
- Как обрабатывать ошибки валидации на фронтенде?