ratelimit¶
cloudg paces every cloud API call with shared adaptive token buckets (per provider / account / region / service), halves a scope's rate when the provider throttles and recovers it gradually (AIMD), honours Retry-After, opens a circuit breaker on a scope that stays throttled, and records it in coverage ("throttled") instead of failing the map.
Unset limits use built-in defaults at or below each provider's published limits (see cloudg/resilience/limiter.py for the numbers and sources). Where keys apply: "AWS hooks" = every boto3/aioboto3 session cloudg builds; "Azure policy" = every Azure SDK client cloudg builds; "GCP" = Cloud Asset Inventory listings. Rate, burst, breaker, adaptive and retry_budget keys apply to all three. Unknown keys are logged and ignored.
Keys¶
| Key | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Turn the shared rate limiter on or off for every provider. |
aws |
map |
||
aws.adaptive |
bool |
true |
Halve a scope's rate when throttled, recover additively (AIMD), all paths |
aws.breaker_threshold |
int |
5 |
Consecutive calls failing on throttling (after retries) that open the circuit of a scope (per operation where the bucket is per operation), all paths |
aws.breaker_cooldown_seconds |
int |
60 |
Seconds an open circuit rejects calls before a probe, all paths |
aws.retry_budget |
int |
500 |
Retries the provider may make before cloudg stops retrying (each success refunds 0.1): AWS hooks, Azure policy, GCP listings, call_with_resilience |
aws.services |
map |
{} |
Per-service overrides of the built-in limits. |
azure |
map |
||
azure.max_retries |
int |
8 |
Retries of a throttled / transient call: Azure SDK retry_total and retry_status, GCP consecutive retries per page, call_with_resilience. Not used by the AWS hooks: botocore retries come from aws.max_retries |
azure.max_backoff_seconds |
int |
60 |
Cap of one backoff sleep: Azure retry_backoff_max, GCP api_core Retry maximum, call_with_resilience. AWS: botocore's own backoff (not configurable here) |
azure.deadline_seconds |
int |
900 |
Overall time budget of one call including retries: Azure RetryPolicy timeout, GCP api_core Retry timeout, call_with_resilience. AWS: botocore timeouts and aws.max_retries bound a call instead |
azure.retry_budget |
int |
500 |
Retries the provider may make before cloudg stops retrying (each success refunds 0.1): AWS hooks, Azure policy, GCP listings, call_with_resilience |
azure.breaker_threshold |
int |
5 |
Consecutive calls failing on throttling (after retries) that open the circuit of a scope (per operation where the bucket is per operation), all paths |
azure.breaker_cooldown_seconds |
int |
60 |
Seconds an open circuit rejects calls before a probe, all paths |
azure.services |
map |
{} |
Per-service overrides keyed by SDK service name (AWS: ec2, iam, ...; Azure: network, compute, resourcegraph, ...; GCP: cloudasset) or ' |
gcp |
map |
||
gcp.max_retries |
int |
8 |
Retries of a throttled / transient call: Azure SDK retry_total and retry_status, GCP consecutive retries per page, call_with_resilience. Not used by the AWS hooks: botocore retries come from aws.max_retries |
gcp.max_backoff_seconds |
int |
60 |
Cap of one backoff sleep: Azure retry_backoff_max, GCP api_core Retry maximum, call_with_resilience. AWS: botocore's own backoff (not configurable here) |
gcp.deadline_seconds |
int |
900 |
Overall time budget of one call including retries: Azure RetryPolicy timeout, GCP api_core Retry timeout, call_with_resilience. AWS: botocore timeouts and aws.max_retries bound a call instead |
gcp.retry_budget |
int |
500 |
Retries the provider may make before cloudg stops retrying (each success refunds 0.1): AWS hooks, Azure policy, GCP listings, call_with_resilience |
gcp.breaker_threshold |
int |
5 |
Consecutive calls failing on throttling (after retries) that open the circuit of a scope (per operation where the bucket is per operation), all paths |
gcp.breaker_cooldown_seconds |
int |
60 |
Seconds an open circuit rejects calls before a probe, all paths |
gcp.services |
map |
{} |
Per-service overrides keyed by SDK service name (AWS: ec2, iam, ...; Azure: network, compute, resourcegraph, ...; GCP: cloudasset) or ' |
live_cooldown_seconds |
int |
120 |
Minimum seconds between two live collections of the same scope (LiveOperationGuard) |
live_max_concurrent |
int |
1 |
concurrent live collections per scope |
live_max_concurrent_total |
int |
2 |
concurrent live collections overall |
live_caller_max_operations |
int |
0 |
Live collections per caller per window (0 = unlimited) |
live_caller_window_seconds |
int |
3600 |
Window of live_caller_max_operations |
live_operation_timeout_seconds |
float | None |
3600.0 |
A live collection running longer is cancelled and its scopes freed (None: no limit) Not in the example file. |
In config.yaml¶
ratelimit:
enabled: true
aws:
# max_rps: 20 # leaf bucket per account x region x service (ec2: per action)
# burst: 40
# account_max_rps: null # aggregate per account (off by default)
# global_max_rps: null # aggregate for all of AWS (off by default)
# max_concurrency: 128 # API calls in flight per account (AWS hooks; botocore's
# retries of a call reuse its slot)
adaptive: true # halve on throttle, recover additively
# min_rps: 0.2 # adaptive floor
breaker_threshold: 5 # calls failing on throttling (after retries) -> open circuit
breaker_cooldown_seconds: 60 # open circuit rejects calls this long, then probes
retry_budget: 500 # botocore retries allowed before cloudg stops retrying
# (each success refunds 0.1; the first two retries
# of every call are free)
# Not used by the AWS hooks (botocore owns per-call retries and timeouts:
# aws.max_retries / aws.retry_mode above); only for call_with_resilience:
# max_retries: 8
# max_backoff_seconds: 60
# deadline_seconds: 900
services: {} # e.g. {ec2: {max_rps: 20, burst: 100}, iam: {max_rps: 5}}
azure:
# max_rps: 15 # per subscription x resource provider
# account_max_rps: 20 # per subscription (ARM: 250 burst / 25 per s)
# account_burst: 200
# max_concurrency: 16 # in-flight HTTP requests per subscription (Azure policy)
max_retries: 8 # azure-core retry_total / retry_status
max_backoff_seconds: 60 # azure-core retry_backoff_max
deadline_seconds: 900 # azure-core RetryPolicy timeout (whole operation)
retry_budget: 500
breaker_threshold: 5
breaker_cooldown_seconds: 60
services: {} # e.g. {resourcegraph: {max_rps: 3, burst: 15}}
gcp:
# max_rps: 10
# max_concurrency: 16 # concurrent Cloud Asset listings per project / org
max_retries: 8 # consecutive api_core retries per page
max_backoff_seconds: 60 # api_core Retry maximum
deadline_seconds: 900 # api_core Retry timeout
retry_budget: 500
breaker_threshold: 5
breaker_cooldown_seconds: 60
services: {} # e.g. {cloudasset.ListAssets: {max_rps: 1.5, burst: 10}}
# Guard rails for live collections triggered on demand (MCP / agents)
live_cooldown_seconds: 120 # min time between live collections of one scope
live_max_concurrent: 1 # concurrent live collections per scope
live_max_concurrent_total: 2 # concurrent live collections overall
live_caller_max_operations: 0 # per caller per window (0 = unlimited)
live_caller_window_seconds: 3600
# live_operation_timeout_seconds: 3600 # cancel a live collection running longer (null: no limit)
Read from the annotated example config.yaml and the CloudGConfig models in cloudg/config.py.