Nicholas Pini
08/07/2026, 5:29 PMMarvin
08/07/2026, 5:29 PMMarvin
08/07/2026, 5:32 PMDEFAULT is effectively:
INPUTS + TASK_SOURCE + RUN_ID
- RUN_ID is based on the immediate flow run context, not the root/root-parent flow run.
- So when a parent flow retries and launches a subflow again, that subflow gets a new flow run ID, which changes the cache key for tasks inside it.
That means the default behavior is intentionally scoped to the current flow run lineage at the immediate parent level, and it will not naturally reuse caches across subflow re-creation during parent retries.
So is your approach correct?
Yes. Using a custom cache policy keyed on:
- task inputs
- task source
- root_flow_run_id
is a sensible way to make cache reuse survive parent-flow retries that recreate subflows.
Is it idiomatic?
I’d say: yes, when that’s the behavior you want. Prefect gives you composable cache policies specifically so you can tune cache scope.
That said, there are two design choices here:
1. Scope cache to one top-level flow execution
- Your root_flow_run_id approach
- Good when you want reuse across retries of the same overall run, but not across separate top-level flow runs
2. Scope cache purely by data/code identity
- e.g. INPUTS, or INPUTS + TASK_SOURCE, or INPUTS + FLOW_PARAMETERS
- Good when you want reuse across entirely separate flow runs too
So the “more idiomatic” answer depends on your intended cache boundary.
When your root_flow_run_id approach is a great fit
Use it if you want:
- cache hits across subflow re-execution during retries
- cache isolation between distinct top-level flow runs
- deterministic reuse only within one overall orchestration attempt tree
That sounds exactly like your use case.
Potential simpler alternative
If you actually don’t care about isolating cache to a single root run, then a built-in policy may be simpler, such as:
- INPUTS + TASK_SOURCE
- or INPUTS + FLOW_PARAMETERS
Those can be more idiomatic if cross-run reuse is acceptable.
Example:
from prefect import task
from prefect.cache_policies import INPUTS, TASK_SOURCE
@task(cache_policy=INPUTS + TASK_SOURCE, persist_result=True)
def my_task(x):
...
But this changes semantics: the cache can be reused by later, unrelated flow runs if inputs/source match.
Recommended guidance
- If you want cache reuse only within retries of one root flow run, your custom root_flow_run_id policy is the right approach.
- If you want cache reuse across separate runs too, prefer a built-in composition like INPUTS + TASK_SOURCE.
One thing to watch
Be sure persist_result=True is enabled, otherwise there’s nothing durable to reuse.
Relevant docs / references
- Caching concepts: Prefect caching docs
- Cache policies API: prefect.cache_policies
- Runtime context: prefect.runtime.flow_run
If you want, I can help sketch a clean CacheKeyFnPolicy for root_flow_run_id using Prefect 3.4.9 conventions.