Yes — that request volume makes sense for Prefect Cloud once you combine:
-
325 separate trigger events / flow runs
-
subflows (which create their own flow runs)
-
tasks (each with state transitions and orchestration updates)
So even though you dropped
325 files, Prefect may easily generate
thousands of API interactions.
Important detail: in Prefect 3.x,
subflows create separate flow runs. They are not just inline function calls. That means every subflow adds more orchestration/state traffic.
Given your numbers, you’re likely seeing amplification from:
- one automation-triggered deployment run per file
- parent flow state changes
- subflow run creation/state changes
- task run creation/state changes
- result/future resolution and dependency tracking
About increasing the limit
If you need a higher Cloud API rate limit, that’s generally a
plan/account-level question rather than a runtime setting you can tune yourself here.
- Check pricing / plans:
prefect.io/pricing
- For anything beyond self-serve options:
contact Prefect
- Your current usage page:
rate limits
What I’d recommend technically
The biggest lever is usually to
reduce the number of flow runs, not just tasks.
1.
Batch files instead of one flow run per file
- Instead of triggering 325 flow runs, trigger one flow run per batch/window of files.
- Example: accumulate files for 1–5 minutes, then process a list of keys in a single flow.
2.
Avoid subflows when tasks are enough
- If a subflow is just being used for code organization, convert it to a task or plain Python function where possible.
- Subflows add orchestration overhead because they create separate flow runs.
3.
Reduce trigger fan-out
- If your automation is effectively “one event => one deployment run”, that’s the main source of the burst.
- Consider a batching pattern:
- S3 event writes metadata somewhere
- one scheduled or event-debounced flow picks up many files at once
4.
Use tasks for per-file work inside one flow
- A single flow can process many files as tasks, optionally concurrently.
- That still creates API traffic, but usually
much less than hundreds of separate parent/subflow trees.
5.
Add backpressure / throttling at ingestion
- If files land in bursts, intentionally stagger processing so flow creation is spread over time.
A better pattern for your case
Instead of:
- 325 S3 object-created events
- 325 flow runs
- each flow calling subflows
- each subflow calling tasks
Prefer something like:
- S3 events record object keys
- one scheduled/debounced flow runs every minute
- that flow loads up to N keys
- processes them in tasks inside a single flow run
Something like:
@flow
def process_s3_batch(file_keys: list[str]):
futures = [process_file.submit(key) for key in file_keys]
return [f.result() for f in futures]
@task
def process_file(key: str):
...
That architecture usually helps much more than trying to raise the rate limit alone.
Rule of thumb
If you have many small units of work:
- use
one flow run for orchestration of a batch
- use
tasks for item-level processing
- use
subflows only when you truly need separate flow-run visibility/retries/isolation
If you want, I can help you redesign your current S3-triggered setup into a
batching/debouncing pattern that keeps the same behavior but dramatically reduces API calls.