Capacity Governor
Capacity Governor — асинхронная Python-библиотека, которая решает, кому сколько дефицитного ресурса дать прямо сейчас и когда этот ресурс пополнять. Основной читатель — разработчик Python 3.11+, у которого несколько потребителей делят пул ограниченных ресурсов и мешают друг другу.
Библиотека не хранит ресурсы и не выполняет работу. Она считает окно каждого потребителя — сколько работы ему разрешено держать в полёте — и отдаёт это число вашему коду, который его применяет.
Когда она нужна
Возьмите её, если узнаёте свою ситуацию:
- один пул делят несколько заданий, и крупное забивает его целиком, а мелкие ждут;
- ресурс кончается в середине работы, и очередь копит ошибки вместо того, чтобы ждать;
- вы развели потребителей по жёстким лимитам в конфиге, и теперь половина лимитов простаивает, пока другая упирается в потолок;
- пополнение (регистрация аккаунтов, закупка ключей) запускается то поздно, то дважды;
- приоритет сделан через
sleepи ручные правки конфига во время инцидента.
Ресурс при этом может быть каким угодно: аккаунты платформ, прокси, слоты браузеров и GPU, ключи внешних API с квотой, номера для SMS, предоплаченные кредиты. Библиотеке важно не что это, а как оно расходуется.
Она не нужна, если ресурс один на одного потребителя, если лимит статичен и никого не стесняет, или если очередь и так простаивает — делить там нечего.
Установка
uv add capacity-governor
Ядро не имеет зависимостей вообще. Адаптер к PostgreSQL ставится отдельно:
uv add "capacity-governor[postgres]"
Как это выглядит
Двенадцать прокси на три задания скрапинга, одно из которых вдвое важнее:
from capacity import ConsumerState, MaxMinFair
policy = MaxMinFair()
allocation = policy.allocate(
capacity=12,
consumers=[
ConsumerState("urgent-scrape", demand=500, weight=2),
ConsumerState("daily-scrape", demand=500),
ConsumerState("backfill", demand=500),
],
deficits={},
)
allocation.grants # {'urgent-scrape': 6, 'daily-scrape': 3, 'backfill': 3}
Политика — чистая функция: те же аргументы дают тот же ответ, базы и времени она не знает. Её можно вызвать прямо в своём планировщике, а можно обернуть в контур, который сам пересчитывает окна по расписанию:
scope = PostgresTickScope(session_scope=sessionmaker, scope="scrapers")
governor = Governor(
scope=scope,
capacity_source=proxy_pool, # сколько прокси живо
registry=jobs, # кто и сколько просит
windows=job_windows, # куда применить окна
state=PostgresStateStore(scope),
policy=MaxMinFair(min_hold_ticks=5),
clock=clock,
stabilizer=Stabilizer(),
)
await governor.run(every=timedelta(seconds=5), stop=shutdown)
Контур берёт лидерство на каждый такт, пишет только изменившиеся окна и переживает перезапуск: очередь и удержания лежат в базе, а не в памяти процесса.
Сценарии
Четыре разбора под разные виды ресурса — с кодом, который запускается без базы:
| Сценарий | Про что | Код |
|---|---|---|
| Прокси между скраперами | веса, освобождение доли, падение ёмкости | examples/proxy_pool.py |
| Слоты GPU между командами | гарантированный минимум и потолок | examples/gpu_slots.py |
| Отправители рассылки | последовательный расход, переключение | examples/mailing_senders.py |
| Квота внешнего API | когда докупать и сколько | examples/api_quota.py |
python -m examples.proxy_pool
Что внутри
Политики распределения отвечают на вопрос «кому сколько сейчас»:
MaxMinFair— общий пул между несколькими потребителями: веса, гарантированный минимум, потолок, честная ротация, когда ресурса меньше, чем просят;Sequential— выделенный пул с последовательным расходом, где чередование ресурсов вредно;StaticCeiling— статичный потолок для ресурсов, которым пересчёт не нужен.
Политика пополнения отвечает на вопрос «когда заводить ещё»:
ReorderPoint— планка «упало ниже — дозаказать до цели», правило «не хватает под уже поставленную работу», бюджет заказов за окно и учёт того, что уже едет.
Контур применяет политику сам: раз в несколько секунд читает ёмкость и спрос, гасит
дрожание окон, пишет только изменения, заказывает пополнение и отдаёт метрики такта.
Оператор вмешивается командами pin, unpin, pause, resume.
Подробнее — docs/architecture.md.
Интеграции
Порты — обычные Protocol, поэтому подключить можно что угодно. Готовые адаптеры:
| Адаптер | Что даёт | Extras |
|---|---|---|
capacity_adapters.memory |
всё в памяти: примеры, тесты, прототипы | — |
capacity_adapters.postgres |
лидерство на advisory-локе, состояние, pin/pause |
[postgres] |
capacity_adapters.tallyho |
спрос и окна одним запросом, заказ пополнения | [tallyho] |
capacity_adapters.identity_hub |
ёмкость пула аккаунтов через Identity Hub | [identity-hub] |
Адаптеры к Tallyho и Identity Hub написаны против их публичных сигнатур и сами эти пакеты не импортируют — их можно читать и тестировать, не устанавливая ни один из них.
Разработка
python -m venv .venv && .venv/bin/pip install -e ".[dev,postgres]" asyncpg
pytest -q # 273 теста: политики, контур, адаптеры, симуляция, интеграция
python -m sim # прогоны симуляции: как ведут себя параметры под нагрузкой
ruff check . && mypy src tests sim
Интеграционные прогоны требуют PostgreSQL и без него пропускаются:
docker run -d --name capacity-governor-test-pg \
-e POSTGRES_PASSWORD=capacity -e POSTGRES_USER=capacity \
-e POSTGRES_DB=capacity -p 55444:5432 postgres:16-alpine
CAPACITY_TEST_DSN задаёт подключение. Порядок выпуска — в
docs/releasing.md, изменения — в CHANGELOG.md.
Лицензия
MIT — см. LICENSE.
Metadata
Release files for capacity-governor 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| capacity_governor-0.2.0.tar.gz | 132.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| capacity_governor-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 179.5 kB
Release files / capacity_governor-0.2.0.tar.gz
| Download URL | capacity_governor-0.2.0.tar.gz |
|---|---|
| Size | 132.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b885a6d7918e8626eb6fefdef35fe64404657bfbb57f01bcc3f0727586b26de8
|
|
BLAKE2b-256 checksum How to use checksums |
4126ef4b2994620fddd0bf6205c784c99be1c0fd46dc7b0d2d423a66b9a61a1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / capacity_governor-0.2.0-py3-none-any.whl
| Download URL | capacity_governor-0.2.0-py3-none-any.whl |
|---|---|
| Size | 47.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f780a1ab268a0b707612e68ba42052c4185639fac7aec90518bec08b3fed756
|
|
BLAKE2b-256 checksum How to use checksums |
76a9900c65b2b213c0beb8315874ec8d77b0495e7cb353cd01778f093a2842b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for capacity-governor 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for capacity_governor-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.