Billy McMonagle
03/16/2026, 8:58 PMMarvin
03/16/2026, 8:58 PMMarvin
03/16/2026, 9:00 PMprefect gcl create my-api --limit 100 --slot-decay-per-second 100
- Throttle request rate (recommended for API rate limits)
from prefect import flow, task
from prefect.concurrency.sync import rate_limit
@task
def call_api(i: int):
rate_limit("my-api") # waits if needed, then immediately releases
return requests.get(f"<https://api.example.com/items/{i}>").json()
@flow
def main():
for i in range(1000):
call_api.submit(i)
- Cap simultaneous in-flight calls (use if the API or your resources also have a concurrency cap)
from prefect import flow, task
from prefect.concurrency.sync import concurrency
@task
def call_api(i: int):
with concurrency("my-api-concurrent", occupy=1): # holds a slot for the duration
return requests.get(f"<https://api.example.com/items/{i}>").json()
@flow
def main():
for i in range(1000):
call_api.submit(i)
Combining both
- Many APIs have both: “N requests/sec” and “no more than M concurrent requests.” Use rate_limit for the throughput cap and concurrency for the in-flight cap with two different GCLs.
Caveats
- rate_limit will error if the corresponding GCL does not have slot_decay_per_second set.
- concurrency has lease_duration (default 300s). For very long tasks consider adjusting it; strict=True enforces correctness if leases can’t be renewed.
References
- Concepts: Global concurrency & rate limits (Prefect 3)
- How-to: Enforcing global concurrency & rate limits
- Implementation: prefect.concurrency.asyncio
If you can share your API’s exact limits (e.g., “100 req/sec with bursts of 200; max 20 concurrent”), I can sketch the precise GCL settings and code pattern.