> Как решить проблему повторного запроса при переводе денег, чтобы избежать двойного списания? (Python)

Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: HeadHunter

Стек: Python

> Пример ответа

Для решения проблемы повторного запроса при переводе денег и предотвращения двойного списания используется идемпотентность. Основной подход - внедрение ключа идемпотентности (Idempotency Key) на стороне клиента или сервера.

Пример реализации на Python:

  1. Генерация и передача ключа: Клиент отправляет уникальный idempotency_key (например, UUID) в заголовке запроса.
  2. Проверка на сервере: Сервер проверяет, был ли уже обработан запрос с таким ключом. Если да - возвращает предыдущий результат, не выполняя операцию повторно.
  3. Атомарность: Используйте транзакции базы данных с блокировкой или атомарные операции (например, INSERT ... ON CONFLICT DO NOTHING в PostgreSQL).
PYTHON
import uuid
from flask import Flask, request, jsonify
from your_db import db # гипотетическая БД
app = Flask(__name__)
@app.route('/transfer', methods=['POST'])
def transfer_money():
idempotency_key = request.headers.get('Idempotency-Key')
if not idempotency_key:
return jsonify({'error': 'Missing idempotency key'}), 400
# Проверяем, был ли уже обработан запрос
existing = db.fetch_one(
"SELECT status FROM transfers WHERE idempotency_key = %s",
(idempotency_key,)
)
if existing:
return jsonify({'status': existing['status']}), 200
# Начинаем транзакцию
try:
# Резервируем ключ атомарно (например, вставляем запись с уникальным ключом)
db.execute(
"INSERT INTO transfers (idempotency_key, status) VALUES (%s, 'pending')",
(idempotency_key,)
)
# Выполняем перевод (списание и зачисление)
# ... логика перевода ...
db.execute("UPDATE transfers SET status = 'completed' WHERE idempotency_key = %s",
(idempotency_key,))
db.commit()
return jsonify({'status': 'completed'}), 200
except IntegrityError: # дубликат ключа
db.rollback()
return jsonify({'status': 'already_processing'}), 409

Дополнительные меры:

  • Используйте распределённые блокировки (например, Redis) для критических секций.
  • Установите TTL для ключей идемпотентности (например, 24 часа).
  • Логируйте все запросы для аудита.

Этот подход гарантирует, что даже при повторной отправке запроса (из-за таймаута или сбоя сети) списание произойдёт только один раз.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью