Сервис принимает платёж через REST, кладёт задачу в очередь и асинхронно её обрабатывает: эмулирует платёжный шлюз и шлёт результат на webhook клиента.
Стек: FastAPI, PostgreSQL, RabbitMQ, Docker Compose.
cp .env.example .env
docker compose up --buildПоднимутся четыре контейнера: postgres, rabbitmq, api, consumer.
- API: http://localhost:8000
- Swagger: http://localhost:8000/docs
- RabbitMQ UI: http://localhost:15672 (логин/пароль
guest/guest)
Если порт 8000 занят — поменяйте маппинг в docker-compose.yml, например "8888:8000".
- Клиент шлёт
POST /api/v1/paymentsс заголовкомIdempotency-Key. - API сохраняет платёж в БД и запись в outbox (в одной транзакции).
- Фоновый relay читает outbox и публикует событие в RabbitMQ.
- Consumer забирает сообщение, «обрабатывает» платёж (2–5 сек, 90% успех) и вызывает webhook.
Повторный запрос с тем же Idempotency-Key не создаст дубль — вернётся уже существующий платёж.
Создать платёж:
curl -X POST http://localhost:8000/api/v1/payments \
-H "Content-Type: application/json" \
-H "X-API-Key: secret-api-key-change-me" \
-H "Idempotency-Key: order-123" \
-d '{
"amount": "1500.00",
"currency": "RUB",
"description": "Test payment",
"metadata": {"order_id": "123"},
"webhook_url": "https://webhook.site/your-unique-id"
}'Ответ — 202, платёж в статусе pending. Дальше consumer сам доведёт до succeeded или failed.
Посмотреть статус:
curl http://localhost:8000/api/v1/payments/{payment_id} \
-H "X-API-Key: secret-api-key-change-me"Все эндпоинты требуют заголовок X-API-Key. Ключ задаётся в .env (API_KEY).
Когда платёж обработан, consumer делает POST на webhook_url:
{
"payment_id": "uuid",
"status": "succeeded",
"amount": "1500.00",
"currency": "RUB",
"description": "Test payment",
"metadata": {"order_id": "123"},
"processed_at": "2026-08-17T12:00:00Z"
}Если webhook не ответил — 3 попытки с паузами 1, 2 и 4 секунды. Не помогло — сообщение уходит в DLQ (payments.new.dlq), смотреть в RabbitMQ UI → Queues.
Нужны PostgreSQL и RabbitMQ на машине.
python -m venv .venv && source .venv/bin/activate
pip install -e ".[test]"
cp .env.example .env # поправьте URL под localhost
alembic upgrade head
uvicorn app.main:app --reload # терминал 1
faststream run app.consumer.main:app # терминал 2pip install -e ".[test]"
pytest| Переменная | Зачем |
|---|---|
DATABASE_URL |
PostgreSQL, формат postgresql+asyncpg://user:pass@host:5432/db |
RABBITMQ_URL |
RabbitMQ, формат amqp://guest:guest@host:5672/ |
API_KEY |
Значение для заголовка X-API-Key |
OUTBOX_POLL_INTERVAL_SECONDS |
Как часто relay проверяет outbox (секунды, по умолчанию 2) |
Примеры значений — в .env.example.