3.7 KiB
3.7 KiB
Обработка ошибок
Матрица ошибок по слоям
| Слой | Что делаем | Пример |
|---|---|---|
| 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 | Ошибки не всплывают выше | Ловим в сервисе |
Иерархия исключений
# 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 (для внешних вызовов)
# Паттерн для всех вызовов внешних 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
Когда внешний сервис недоступен:
- DB недоступна → 503 Service Unavailable
- Redis недоступен → работаем без кэша (log WARNING)
- AI провайдер недоступен → возвращаем fallback результат
- Celery недоступен → выполняем задачу синхронно
[ASK] Вопросы по обработке ошибок
- Нужны ли пользовательские исключения для всех бизнес-сценариев?
- Нужен ли sentry или аналогичный мониторинг ошибок?
- Как обрабатывать ошибки валидации на фронтенде?