Skip to content

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 '.' (e.g. cloudasset.ListAssets)
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 '.' (e.g. cloudasset.ListAssets)
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

config.yaml (ratelimit)
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.