Configuration¶
Everything sits under ratelimit in config.yaml (CloudGConfig.ratelimit, a RateLimitConfig). The section is additive: a config without it behaves exactly as the built-in defaults above. Unset (null) provider limits fall back to the built-ins; service overrides are merged into the built-in service table key by key.
A key that is not part of the models below, at any level of ratelimit (ratelimit, ratelimit.<provider>, ratelimit.<provider>.services.<name>), is ignored with a warning, and the rest of the config still loads:
5.1 ratelimit¶
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled |
bool | true |
Master switch. false turns off pacing, breakers, cloudg-level retries and the Azure retry overrides for every provider. botocore keeps its own retries from aws.max_retries / aws.retry_mode, and coverage still labels throttling errors |
aws, azure, gcp |
ProviderRateLimitConfig |
all defaults | Per-provider settings (5.2) |
live_cooldown_seconds |
float >= 0 | 120 |
Minimum time between two live collections of the same scope |
live_max_concurrent |
int, 1 to 64 | 1 |
Live collections allowed at once per scope |
live_max_concurrent_total |
int, 1 to 256 | 2 |
Live collections allowed at once overall |
live_caller_max_operations |
int >= 0 | 0 |
New live collections per caller per window; 0 means unlimited |
live_caller_window_seconds |
float > 0 | 3600 |
Length of that window |
live_operation_timeout_seconds |
float > 0 or null | 3600 |
A live collection running longer is cancelled and its scopes freed; null means no limit |
5.2 ratelimit.<provider>¶
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled |
bool | true |
Pace and circuit-break this provider. false makes its calls go straight to the SDK |
max_rps |
float > 0 or null | built-in (AWS 20, Azure 15, GCP 10) | Default leaf rate per account x region x service |
burst |
float > 0 or null | built-in (AWS 40, Azure 100, GCP 20) | Default leaf capacity |
account_max_rps |
float > 0 or null | built-in (Azure 20, others off) | Aggregate rate per account, subscription or project |
account_burst |
float > 0 or null | built-in (Azure 200), else twice account_max_rps |
Capacity of the account bucket |
global_max_rps |
float > 0 or null | off | Aggregate rate for every call to this provider in the process |
global_burst |
float > 0 or null | twice global_max_rps |
Capacity of the provider-wide bucket |
max_concurrency |
int, 1 to 1024, or null | built-in (AWS 128, others 16) | Requests in flight per account (bulkhead, section 2.5) |
adaptive |
bool | true |
Halve a scope's rate on throttling and recover additively |
min_rps |
float > 0 or null | built-in (AWS 0.2, Azure 0.1, GCP 0.05) | Floor of the adaptive rate |
breaker_threshold |
int, 1 to 1000 | 5 |
Consecutive calls that failed on throttling or transient errors after their retries before the circuit opens |
breaker_cooldown_seconds |
float >= 0 | 60 |
How long an open circuit rejects calls before a probe; doubles on each failed probe up to 600 |
max_retries |
int, 0 to 50 | 8 |
Retries of a throttled or transient call: azure-core retry_total / retry_status, consecutive api_core retries per GCP page, call_with_resilience. AWS SDK retries use aws.max_retries |
max_backoff_seconds |
float > 0 | 60 |
Cap of one backoff sleep: azure-core retry_backoff_max, api_core Retry(maximum=), call_with_resilience |
deadline_seconds |
float > 0 | 900 |
Overall time for one call including retries: azure-core RetryPolicy(timeout=), api_core Retry(timeout=), call_with_resilience |
retry_budget |
int >= 0 | 500 |
Retries per provider, across every integration, before retrying stops; each success refunds 0.1 |
services |
map of name to ServiceRateLimitConfig |
{} |
Per-service or per-operation overrides (5.3) |
live_cooldown_seconds |
float >= 0 or null | null | Overrides ratelimit.live_cooldown_seconds for live scopes of this provider |
5.3 ratelimit.<provider>.services.<name>¶
The key is the SDK service name (AWS: ec2, iam, sts, s3, ...; Azure: network, compute, storage, resources, resourcegraph, ...; GCP: cloudasset) or <service>.<Operation> for one operation (ec2.DescribeImageAttribute, cloudasset.ListAssets). An operation key always gets its own bucket.
| Key | Type | Default | Meaning |
|---|---|---|---|
max_rps |
float > 0, required | Sustained requests per second | |
burst |
float > 0 or null | twice max_rps |
Bucket capacity. An override replaces the whole built-in entry, so give the burst again if you want to keep it (the built-in ec2 burst of 100 becomes 20 if you set only max_rps: 10) |
per_operation |
bool or null | the built-in choice (true for AWS ec2) |
One bucket, and one circuit breaker, per API operation instead of one per service |
5.4 Where each key takes effect¶
The four integrations are the AWS hooks (botocore event hooks on every boto3 and aioboto3 session cloudg builds), the Azure policy (the per-attempt pipeline policy plus the explicit RetryPolicy on every Azure SDK client, Resource Graph included), the GCP Cloud Asset Inventory listings, and call_with_resilience for your own code.
| Key | AWS hooks | Azure policy | GCP listings | call_with_resilience |
|---|---|---|---|---|
enabled, max_rps, burst, services (with per_operation) |
yes | yes | yes | yes |
account_max_rps, account_burst |
yes | yes (default 20 / 200) | yes | yes |
global_max_rps, global_burst |
yes | yes | yes | yes |
adaptive, min_rps |
yes | yes | yes | yes |
breaker_threshold, breaker_cooldown_seconds |
yes (per operation for EC2) | yes | yes | yes |
max_concurrency |
per API call, per account | per HTTP attempt, per subscription | per concurrent listing, per project or organization | per call |
retry_budget |
yes, stops botocore's retries | yes, stops azure-core's retries | yes, stops api_core's retries | yes |
max_retries |
no: botocore uses aws.max_retries |
retry_total and retry_status |
consecutive retries per page | yes |
max_backoff_seconds |
no: botocore's own backoff | retry_backoff_max |
api_core Retry maximum |
yes |
deadline_seconds |
no: botocore's timeouts and aws.max_retries bound a call |
RetryPolicy timeout (whole operation) |
api_core Retry timeout |
yes |
aws.max_retries, aws.retry_mode |
botocore retries (counted after the first attempt; default adaptive, 10) | n/a | n/a | n/a |
live_*, <provider>.live_cooldown_seconds |
LiveOperationGuard only |
In every integration the first two retries of a call (of a page, for GCP) are free and never draw on retry_budget.
Resource Graph pages fetched through _fetch_page with a client from a custom factory also retry a 429 up to QueryLimits.max_retries (5) times themselves; clients cloudg builds leave that to azure-core (section 3.3).
5.5 Examples¶
An organization-wide AWS map with many accounts, plus Azure and GCP estates that other teams also query. This leaves more of each account's quota to everyone else and keeps one account from absorbing the whole run:
ratelimit:
aws:
max_rps: 8 # every account x region x service bucket
burst: 16
account_max_rps: 40 # all services of one account together
global_max_rps: 200 # all of AWS from this process
max_concurrency: 64 # requests in flight per account
min_rps: 0.1
breaker_cooldown_seconds: 120
services:
ec2: {max_rps: 10, burst: 50} # still one bucket per EC2 action
iam: {max_rps: 4, burst: 8}
cloudcontrol: {max_rps: 2, burst: 4}
azure:
account_max_rps: 10 # per subscription
services:
resourcegraph: {max_rps: 1, burst: 5}
gcp:
services:
cloudasset.ListAssets: {max_rps: 0.5, burst: 5}
live_cooldown_seconds: 600
One noisy service. The tagging API in this account is shared with a cost tool that already uses most of its quota, and one AMI-heavy region needs its attribute calls slowed down without touching the rest of EC2:
ratelimit:
aws:
services:
resourcegroupstaggingapi: {max_rps: 1, burst: 2}
ec2.DescribeImageAttribute: {max_rps: 5, burst: 10}
Turning it off, everywhere or for one provider:
All four examples were loaded through CloudGConfig.model_validate and Governor(config) to check the resulting limits. In code:
from cloudg import CloudGConfig
config = CloudGConfig.model_validate(
{"ratelimit": {"aws": {"max_rps": 8, "services": {"iam": {"max_rps": 4}}}}}
)
config.ratelimit.live_cooldown_seconds = 600
The shipped config.yaml has a commented ratelimit section with the defaults.