Маркетплейс интегрировался с 12 платёжными шлюзами и службами доставки. Падение одного внешнего сервиса не должно тянуть за собой всю платформу. Мы внедрили Circuit Breaker через библиотеку pybreaker:
# circuit_breaker.py
import pybreaker
import requests
# Конфигурация Circuit Breaker для платёжного шлюза
payment_breaker = pybreaker.CircuitBreaker(
fail_max=5, # 5 ошибок подряд → размыкание
reset_timeout=30, # через 30 секунд пробуем снова
exclude=[requests.exceptions.Timeout], # таймауты не считаем
)
@payment_breaker
def process_payment(order_id, amount, gateway='primary'):
response = requests.post(
f'https://api.{gateway}-pay.ru/v1/charge',
json={'order_id': order_id, 'amount': amount},
timeout=5,
)
response.raise_for_status()
return response.json()
def process_payment_with_fallback(order_id, amount):
try:
return process_payment(order_id, amount, gateway='primary')
except pybreaker.CircuitBreakerError:
# Основной шлюз недоступен — переключаемся на резервный
return process_payment(order_id, amount, gateway='backup')
Для Rate Limiting мы использовали алгоритм Token Bucket через Redis, ограничивая API на уровне пользователя:
# rate_limiter.py
import redis
import time
r = redis.Redis(host='redis-sentinel', port=6379)
def check_rate_limit(user_id, max_requests=100, window=60):
key = f'ratelimit:{user_id}:{int(time.time()) // window}'
pipe = r.pipeline()
pipe.incr(key)
pipe.expire(key, window + 1)
result = pipe.execute()
current = result[0]
if current > max_requests:
return False, max_requests - current # отклонить
return True, max_requests - current # пропустить
Каждый пользователь ограничен 100 запросами в минуту. Для API-партнёров лимит увеличен до 1 000 req/min с отдельным ключом.
Оставить комментарий