Поэтому я написал одну, которая объединяет всё.
Когда простой API-клиент превращается в зоопарк
Любой проект начинается с чего-то такого:
import httpx async def fetch_user(user_id: str): async with httpx.AsyncClient() as client: r = await client.get(f"https://api.example.com/users/{user_id}") return r.json()
А потом реальность:
API лимитирует запросы
иногда отвечает 503
иногда виснет
иногда падает полностью
и retry может убить уже ваш сервис
И начинается подключение библиотек:
rate limit
retry
circuit breaker
И функция превращается в это:
@breaker @retry(...) @sleep_and_retry @limits(...) async def fetch_user(...): ...
Формально всё работает.
Но появляется ощущение, что ты не пишешь бизнес-логику.
Ты пишешь инфраструктурный клей.
Главная проблема — не в библиотеках
Каждая библиотека сама по себе нормальная.
Проблема в композиции:
разные модели времени
разные абстракции ошибок
разные API
сложное тестирование
непредсказуемое поведение при нагрузке
Retry + limiter + breaker — это уже система.
А мы собираем систему из несвязанных кусочков.
Идея: сделать устойчивость конвейером
Вместо “башни декораторов” я хотел одно:
единый pipeline выполнения вызова
Чтобы каждый запрос проходил через понятную схему:
Circuit breaker → Rate limiter → Retry loop → Запись результата
Без магии.
Без хаоса.
Без glue-кода.
Получилось вот так:
from limitpal import ( AsyncResilientExecutor, AsyncTokenBucket, RetryPolicy, CircuitBreaker ) executor = AsyncResilientExecutor( limiter=AsyncTokenBucket(capacity=10, refill_rate=100/60), retry_policy=RetryPolicy(max_attempts=3), circuit_breaker=CircuitBreaker(failure_threshold=5) ) result = await executor.run("user:123", api_call)
Одна точка входа.
Одна модель поведения.
Одна архитектура.
Почему это важно
Retry без limiter — опасен.
Limiter без breaker — слеп.
Breaker без retry — жёсткий.
Только вместе они образуют стратегию устойчивости.
Именно стратегия, а не набор фич.
Тестирование — скрытая боль
Самая неприятная часть таких систем — время.
Традиционно:
time.sleep(1)
Медленно.
Флейково.
Непредсказуемо.
Поэтому внутри используется управляемые часы:
clock.advance(1.0)
Тесты выполняются мгновенно, но поведение идентично реальному.
Это звучит как мелочь.
На практике — спасение для CI и нервов.
Что в итоге получилось
Я собрал всё в одну библиотеку — LimitPal.
Это не “ещё один rate limiter”.
Это попытка сделать устойчивость архитектурным примитивом:
rate limiting
retry с backoff и jitter
circuit breaker
композиция стратегий
sync + async API
детерминированные тесты
Без внешних зависимостей.
Когда это имеет смысл
Если вы:
пишете API-клиенты
ходите во внешние сервисы
делаете фоновые джобы
боитесь retry-штормов
хотите предсказуемое поведение под нагрузкой
тогда архитектурный подход окупается.
Если нужен только retry — можно взять маленькую либу.
Но как только появляется композиция — начинается системная инженерия.
Документация:
https://limitpal.readthedocs.io/
Репозиторий:
https://github.com/Guli-vali/limitpal
Если идея зашл — буду рад обратной связи.
Комментарии (7)

mgis
06.02.2026 07:17Простите, почему нельзя просто?
npx @openapitools/openapi-generator-cli generate \ -i http://localhost:8000/openapi.json \ -g typescript-axios \ -o ./src/api/generatedp.s. ни разу не фронтендер.

maslievilya1 Автор
06.02.2026 07:17Спасибо за комментарий, не совсем понял что вы имели ввиду. Дело не в самом клиенте к API, а в упаравлении обработке "скользких" мест такие как рейт лимиты, ретраи и т д. То есть моя боль была скорее в том что на питоне нет библиотеки с единным пайплайном для контроля нагрузки и устойчивости.
Flux82
А я почему-то чувствую клоунами тех, кто клепает на llm без оглядки новые либы (помните xkcd про новый стандарт, кстати?) и нейростатьи к ним тысячами. И нет, опечатка в конце не делает тест естественным.
maslievilya1 Автор
Я понимаю ваше негодование от массы безликих ЛЛМ продуктов и статей. Но обьективности ради, не все проекты где используются ЛЛМ плохие по дефолту. Было здорово все таки жить в парадигме презумпции невиновности.
Моя библиотека результат конкретной боли, и представляет собой конкретное решение моей боли, ничего больше:) Буду рад обьективной критике: если где то есть проблемы в самой библиотеке, или если она сможет помочь вам в похожей ситуации, хорошего вам дня и спасибо за комментарий!
Flux82
Не отношу себя к неолуддитам. Получив от вас ответ, хочется прокомментировать. Я не написал бы достаточно резкий комментарий, если бы сама библиотека был описана вами. Однако здесь я вижу не только код, написанный вами с помощью LLM за одну-две недели, но и насквозь нейросетевой пост с громкими словами. Если бы не было громких слов, если бы чётко была вынесена роль LLM в написании либы, если бы примеры были привязаны к большему количеству реальных задач, реакция была бы другой.
maslievilya1 Автор
Огромное спасибо за конструктивную критику и взгляд со стороны, которого лично мне не хватает как автору!
В продолжение дискуссии соглашусь с вами, что статья может звучать громко и пафосно - она была нарочно написана в таком маркетингово-рекламном стиле, в противовес моей предыдущей технически «нагруженной» статье.
Если вам по душе более хабровый стиль и вас правда заинтересовала техническая часть без маркетинга и пафоса, то приглашаю почитать более развернутый вариант статьи на 12 минут - с логикой архитектурных решений, примерами кода и общей логикой проблем и решений:
https://habr.com/ru/articles/992902/
Также приглашаю вас почитать более раннюю статью, где я рассказывал про свой опыт, который сформировал видение проблемы и вдохновил меня на создание библиотеки:
https://habr.com/ru/articles/983066/
Чтобы закрыть вопрос о роли ИИ в написании библиотеки:
Документация (докстринги, документирование аргументов классов/методов, генерация техдокументации)
Роль ИИ: помог дотянуть репозиторий до стандартов документирования open source-проектов, что особенно непросто для соло-девелоперов.
Моя роль: контроль логики и достоверности документации.
Тесты
Роль ИИ: генерация тестов по заданному мной плану покрытия функционала тестами.
Моя роль: контроль корнер-кейсов (переполнение памяти), соблюдение таймингов лимитеров, решение использовать pluggable-модель времени для тестов и т.д.
Контроль thread-safety и работа с памятью
Роль ИИ: учитывая, что моя библиотека (на данный момент) in-memory и исповедует бакет-ориентированную архитектуру лимитирования, в теории могли возникать проблемы с памятью из-за переполнения ключами, а также гонки состояний, особенно в синхронном варианте моих алгоритмов лимитирования. ИИ помог выявить потенциально проблемные места, которые человеческий глаз может упустить.
Моя роль: иметь представление о возможных корнер-кейсах и картину надежности с точки зрения того, что и где стоит предусмотреть.
Искренне благодарен за интерес к проекту!
SiberianMouse
Ну да, ладно там, код написал клауде, или кто там чат гпт, но текст можно было уместить в два абзаца и написать от руки, пока правишь ошибки все равно же вникаешь в суть, и передал бы ее своими словами, пусть они будут дилетантскими.