Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Асинхронный сервис процессинга платежей

Сервис реализует тестовое задание: принимает платеж, сохраняет его в PostgreSQL, публикует событие в RabbitMQ через outbox, обрабатывает платеж в consumer и отправляет webhook о результате.

Что внутри

  • FastAPI + Pydantic v2
  • SQLAlchemy 2.0 async
  • PostgreSQL
  • RabbitMQ + FastStream
  • Alembic
  • Docker Compose
  • Idempotency-Key
  • Outbox pattern
  • Retry с экспоненциальной задержкой
  • Dead Letter Queue

Структура

app/
  api/
  clients/
  core/
  db/
  models/
  repositories/
  schemas/
  services/
scripts/
alembic/

Быстрый запуск

cp .env.example .env
docker compose up --build

Сервисы:

  • API: http://localhost:8000
  • Swagger: http://localhost:8000/docs
  • RabbitMQ UI: http://localhost:15672
  • Webhook mock: http://localhost:8010
  • PostgreSQL: localhost:5432

Как это работает

  1. POST /api/v1/payments принимает запрос и Idempotency-Key.
  2. В одной транзакции сохраняются payments и запись в outbox.
  3. API-фон публикует событие в RabbitMQ.
  4. Consumer получает сообщение из payments.new.
  5. Эмулируется платёжный шлюз: задержка 2-5 сек, 90% успеха.
  6. Статус платежа обновляется в БД.
  7. Отправляется webhook.
  8. Если webhook не ушёл, сообщение уходит в retry-очередь.
  9. После 3 неудач сообщение уходит в payments.dlq.

Очереди

  • payments.new — основная очередь
  • payments.retry.1 — retry через 1 секунду
  • payments.retry.2 — retry через 2 секунды
  • payments.retry.3 — retry через 4 секунды
  • payments.dlq — окончательно упавшие сообщения

Пример запроса

curl --request POST 'http://localhost:8000/api/v1/payments' \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: super-secret-key' \
  --header 'Idempotency-Key: test-payment-1' \
  --data '{
    "amount": "1500.00",
    "currency": "RUB",
    "description": "Оплата заказа #42",
    "metadata": {
      "order_id": "42",
      "customer_id": "100500"
    },
    "webhook_url": "https://example.com/webhook"
  }'

Ответ:

{
  "payment_id": "3f27fdad-76ef-41d3-8eb0-32f2ea74bcfb",
  "status": "pending",
  "created_at": "2026-03-27T10:00:00.000000Z"
}

Получение платежа

curl --request GET 'http://localhost:8000/api/v1/payments/3f27fdad-76ef-41d3-8eb0-32f2ea74bcfb' \
  --header 'X-API-Key: super-secret-key'

Проверка идемпотентности

Повторный POST с тем же Idempotency-Key вернёт уже созданный платёж, новый не создастся.

Проверка webhook

В docker-compose.yml добавлен сервис webhook-mock. Он принимает webhook внутри Docker-сети по адресу:

http://webhook-mock:8080/webhook

С хоста можно смотреть полученные события:

curl http://localhost:8010/events

Сбросить накопленные webhook:

curl -X DELETE http://localhost:8010/events

Настроить временные ошибки webhook для проверки retry и DLQ:

curl -X POST http://localhost:8010/control \
  -H 'Content-Type: application/json' \
  -d '{"failures_remaining": 2, "status_code": 500}'

E2E-проверка webhook:

cd ..
pytest -q -s -m webhook

Тесты показывают:

  • успешную доставку webhook с первой попытки;
  • успешную доставку после retry;
  • уход сообщения в DLQ после исчерпания retry.

Что важно

  • Проект не копируется в Docker image, код подключается через volume.
  • Запуск идёт через shell-скрипты из docker-compose.yml.
  • Миграции выполняются перед стартом API.
  • Топология RabbitMQ поднимается отдельным небольшим скриптом.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages