Skip to content

whxtelyy/payment-distribution-service

Repository files navigation

💳 Payment Distribution Service: Архитектура и Системный дизайн

Высоконагруженный асинхронный микросервис для управления мультивалютными кошельками, проведения транзакций и конвертации валют. Проект спроектирован с упором на отказоустойчивость, финансовую точность и защиту от классических проблем распределенных систем (Race Conditions, Deadlocks, Double Spending).

Примечание: Этот документ описывает не только процесс запуска, но и внутреннюю архитектуру, принятые паттерны проектирования и механизмы обеспечения консистентности данных.


📋 Оглавление

  1. Архитектура системы
  2. Ключевые паттерны и бизнес-логика
  3. Стек технологий
  4. Инфраструктура и Развертывание (Docker)
  5. Тестирование
  6. Быстрый старт

1. Архитектура системы

Система разделена на 4 независимых компонента, общающихся в изолированной сети Docker:

  • API Gateway / Core Service (FastAPI): Принимает запросы пользователей, валидирует данные, взаимодействует с БД и отправляет задачи в очередь. Работает в полностью асинхронном режиме.
  • Relational Database (PostgreSQL): Хранит состояние кошельков, пользователей и историю транзакций. Является единым источником истины (Single Source of Truth), обеспечивает выполнение ACID-требований.
  • In-Memory Cache & Message Broker (Redis): Выполняет три роли:
    1. Брокер сообщений для фоновых задач.
    2. Хранилище распределенных блокировок (Distributed Locks).
    3. Кэш для внешних данных (курсы валют от API ЦБ РФ с TTL = 1 час).
  • Background Worker (Taskiq): Асинхронно обрабатывает «тяжелые» или отложенные задачи (например, финализацию транзакций и отправку уведомлений), снимая нагрузку с основного API.

2. Ключевые паттерны и бизнес-логика

Идемпотентность (Anti-Double Spend)

В распределенных сетях клиент может отправить один и тот же запрос дважды (из-за потери ответа или лага сети). Система защищена от двойного списания средств:

  • Каждый запрос на перевод должен содержать уникальный idempotency_key.
  • При попытке вставить дубликат ключа база данных выбрасывает IntegrityError.
  • Сервис перехватывает ошибку, откатывает транзакцию (db.rollback()) и извлекает результат предыдущего успешного запроса по этому ключу.
  • Защита от коллизий: Если ключ совпадает, но параметры перевода (сумма, получатель) отличаются, транзакция отклоняется с ошибкой Data conflict.

Защита от Deadlocks (Взаимные блокировки)

При встречных переводах (Пользователь А переводит Пользователю Б, и одновременно Пользователь Б переводит Пользователю А) транзакции в БД могут заблокировать друг друга.

  • Решение: Применен паттерн Resource Ordering (Упорядочивание ресурсов).
  • При выполнении SELECT ... FOR UPDATE система всегда сначала блокирует кошелек с наименьшим ID, а затем с наибольшим. Это гарантирует, что все параллельные транзакции выстраиваются в единую однонаправленную очередь ожиданий.

Распределенные блокировки и Воркеры

Чтобы исключить ситуацию (Race Condition), когда несколько инстансов воркера пытаются обработать одну и ту же транзакцию:

  • Используется механизм Distributed Lock на базе Redis (SET key value NX EX 300).
  • Если воркер видит, что блокировка занята, он немедленно завершает работу.
  • Установлен TTL (Time-To-Live) в 300 секунд. Если воркер падает (Out Of Memory, Kernel Panic) во время обработки, блокировка автоматически снимется, и транзакция не зависнет в системе навсегда.
  • При нормальном завершении блокировка гарантированно снимается в блоке finally.

Финансовая точность

  • Использование чисел с плавающей точкой (float) недопустимо в финансовых операциях из-за проблем с представлением дробей в двоичной системе.
  • Все вычисления, включая конвертацию валют по курсу ЦБ, выполняются с использованием типа Decimal.
  • Применяется жесткое квантование (.quantize(Decimal("0.01"))), что исключает появление "микро-копеек" и расхождение балансов.

3. Стек технологий

  • Runtime: Python 3.13+,
  • Backend Framework: FastAPI, Uvicorn (ASGI server)
  • Data validation & Settings: Pydantic v2 (включая pydantic-settings и валидацию email)
  • Database Layer: PostgreSQL 15-aplhine, SQLAlchemy 2.0 (asyncio)
    • Drivers: asynpg, psycopg2-binary (для системных утилит)
    • Mirgations: Alembic
  • Async Task Queue: Taskiq + Taskiq-Redis, Redis 7-aplhine
  • Security & Auth:
    • Tokens: JWT (через PyJWT и python-jose),
    • Hashing: Passlib + Bcrypt (алгоритм Bcrypt)
    • Multipart: python-multipart для обработки сложных запросов
  • Observability:
    • Logging: Python Standart Logging (RotatingFileHandler)
    • Error Tracking: Sentry
  • Deployment & Testing:
    • Testing: Pytest, pytest-asyncio, pytest-mock, httpx (интеграционные тесты)
    • Code Quality: Ruff (linter), Black (formatter), Mypy (static type checking), isort

4. Инфраструктура и Развертывание (Docker)

Проект полностью контейнеризирован и готов к работе в любой среде.

  • Multi-stage build: Dockerfile оптимизирован. Сборка зависимостей и финальный образ разделены, что делает контейнер легким и безопасным.
  • Least Privilege: Приложение внутри контейнера запускается от имени пользователя без прав root (appuser).
  • Healthchecks & Wait-for-it: В docker-compose.yml настроена строгая последовательность запуска. API и Worker стартуют только после того, как PostgreSQL и Redis сообщат о готовности принимать соединения.
  • Auto-Migrations: При старте API контейнер автоматически применяет свежие миграции (alembic upgrade head).

5. Тестирование

Проект покрыт unit- и интеграционными тестами (tests/) с акцентом на тестирование краевых случаев (Edge Cases):

  • Dependency Injection: В тестах реальная база данных подменяется на моки (Mock Objects) через app.dependency_overrides. Это позволяет прогонять сотни тестов за доли секунды без поднятия СУБД.
  • SQLAlchemy Mocks: Написана кастомная фикстура mock_refresh, имитирующая поведение БД после commit() (генерация ID и дефолтных значений).
  • Сценарии:
    1. Аутентификация и Жизненный цикл (test_api.py):
      • Регистрация новых пользователей и валидация уникальности данных.
      • Проверка успешного Login-процесса и выдачи JWT-токенов.
      • Инициализация первого кошелька пользователя и привязка к профилю.
    2. Бизнес-логика транзакций (test_transactions.py):
      • Atomic Transfers: Успешный перевод между кошельками в одной валюте.
      • Currency Exchange: Корректность кросс-валютных переводов с использованием динамических курсов.
      • Verification: Проверка автоматического вызова фоновых задач (Taskiq) для финализации транзакций.
    3. Работа Воркера и Конкурентность (test_worker.py):
      • Happy Path: Полный цикл завершения транзакции фоновым процессом.
      • Race Condition Protection: Проверка механизма предотвращения Double Spending. Если один воркер захватил замок в Redis, второй обязан прервать операцию.
    4. Обработка ошибок и Edge Cases (test_errors.py):
      • Валидация сущностей: Запрет создания дубликатов кошельков или кошельков с несуществующими валютами (USD, RUB, EUR).
      • Безопасность: Проверка защиты эндпоинтов (запрет доступа неавторизованным пользователям).
      • Финансовые ограничения:
        • Блокировка транзакций при недостаточном балансе.
        • Запрет перевода средств «самому себе».
        • Обработка попыток перевода с несуществующих счетов.
      • Reliability: Проверка механизма идемпотентности. Повторный запрос с тем же idempotency_key возвращает старый результат, не создавая новую транзакцию и не списывая средства дважды.

6. Быстрый старт

1. Клонирование репозитория и настройка окружения:

git clone https://github.com/whxtelyy/payment-distribution-service.git
cd payment-distribution-service
cp .env.example .env
# Отредактируйте .env файл, указав свои креды (если необходимо).

В файле .env укажите базовые доступы к БД и SENTRY_DSN (опционально, для работы мониторинга и сбора метрик).

2. Запуск через Docker Compose:

docker-compose up --build

Контейнеры соберутся, БД поднимется, пройдут миграции и запустятся тесты перед стартом сервера. Важно: контейнер api настроен на жесткую проверку: сервер Uvicorn запустится только в том случае, если pytest успешно пройдет все интеграционные тесты внутри изолированной среды.

3. Использование API:

  • Интерактивная документация Swagger доступна по адресу: http://localhost:8000/docs
  • Логи транзакций и работы воркера можно найти в директории app/logs/transaction.log.

About

Пет-проект "Система мультивалютных переводов с фокусом на консистентность данных"

Topics

Resources

Stars

Watchers

Forks

Contributors