Files
voidea/template/docs/08-error-handling.md
T

3.7 KiB
Raw Blame History

Обработка ошибок

Матрица ошибок по слоям

Слой Что делаем Пример
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

Когда внешний сервис недоступен:

  1. DB недоступна → 503 Service Unavailable
  2. Redis недоступен → работаем без кэша (log WARNING)
  3. AI провайдер недоступен → возвращаем fallback результат
  4. Celery недоступен → выполняем задачу синхронно

[ASK] Вопросы по обработке ошибок

  • Нужны ли пользовательские исключения для всех бизнес-сценариев?
  • Нужен ли sentry или аналогичный мониторинг ошибок?
  • Как обрабатывать ошибки валидации на фронтенде?