<@ULVA73B9P> I have an automation that runs when f...
# ask-marvin
t
@Marvin I have an automation that runs when flow runs of specific deployed flows are completed. Is it possible to not run the automation when the flow run is a subflow, using e.g. the
parent_flow_run_id
? Below is the current trigger json:
Copy code
{
  "type": "event",
  "match": {
    "prefect.resource.id": "prefect.flow-run.*"
  },
  "match_related": {
    "prefect.resource.id": [
      "prefect.deployment.<deployment1-id>",
      "prefect.deployment.<deployment2-id>"
    ],
    "prefect.resource.role": "deployment"
  },
  "after": [],
  "expect": [
    "prefect.flow-run.Completed",
    "prefect.flow-run.Cached"
  ],
  "for_each": [
    "prefect.resource.id"
  ],
  "posture": "Reactive",
  "threshold": 1,
  "within": 0
}
m
thought for 505.7 seconds
Short answer: Not with the built‑in automation filters today. - Prefect 3 automations can only match on resource labels via
match
and
match_related
. There’s no NOT/EXISTS operator and no generic “where” filter. - While a subflow’s flow run does have
parent_task_run_id
in the database, that field is not exposed as a filterable event label, so you can’t exclude subflows by checking it in a trigger. - Docs for reference: Event triggers and REST API: Flow runs. Workable patterns you can use instead: 1) Emit a custom event only for top‑level runs and trigger on that - At the end of your flow, check if it’s a root run (no parent) and emit a custom event. - Point your automation at that event name instead of
prefect.flow-run.Completed
. Example flow snippet:
Copy code
from prefect import flow, get_run_context
from prefect.events import emit_event

@flow
def my_flow():
    # ... your logic ...

    # Emit only for top-level runs
    ctx = get_run_context()
    if getattr(ctx.flow_run, "parent_task_run_id", None) is None:
        related = []
        if getattr(ctx.flow_run, "deployment_id", None):
            related.append({
                "prefect.resource.id": f"prefect.deployment.{ctx.flow_run.deployment_id}",
                "prefect.resource.role": "deployment",
            })
        emit_event(
            event="my-org.flow-run.top-level-completed",
            resource={"prefect.resource.id": f"prefect.flow-run.{ctx.flow_run.id}"},
            related=related,
        )
Updated automation trigger (listen for your custom event while still scoping to your deployments):
Copy code
{
  "type": "event",
  "match": {
    "prefect.resource.id": "prefect.flow-run.*"
  },
  "match_related": {
    "prefect.resource.id": [
      "prefect.deployment.<deployment1-id>",
      "prefect.deployment<deployment2-id>"
    ],
    "prefect.resource.role": "deployment"
  },
  "after": [],
  "expect": [
    "my-org.flow-run.top-level-completed"
  ],
  "for_each": [
    "prefect.resource.id"
  ],
  "posture": "Reactive",
  "threshold": 1,
  "within": 0
}
2) Use tags to distinguish top-level vs. subflow runs - If your subflows run via a different deployment, you can tag only the top-level deployment (e.g., tag “top-level”) and filter on
prefect.tag.top-level
in
match_related
. - Caveat: if subflows use the exact same deployment, tags won’t help because they’ll be identical. A quick sanity check: how are your subflows started? - If you call a child
@flow
function directly (not via
run_deployment
), those child runs won’t be associated with a deployment. With your current trigger (which filters by deployment), those subflow runs should already be excluded. - If you launch subflows using
run_deployment
(i.e., child runs are tied to the same deployments), then use approach #1 (custom event) to cleanly separate top-level from subflows. If you’d like, I can file a feature request to support NOT/EXISTS conditions (e.g., “no related task run” or “no parent_task_run_id”) in automation filters.
t
@Marvin So it's not possible to match with None?
m
thought for 14.4 seconds
Correct — not with Prefect 3 automations today. - The trigger language only supports positive inclusion on resource labels via
match
and
match_related
. - There’s no operator for NOT/EXISTS and no way to match “None”/missing fields (e.g., you can’t filter on
parent_task_run_id is None
or “no related task-run”). Docs: Event triggers If you want, I can help you implement the custom-event workaround (emit a special event only for top-level runs) or file a feature request for null/negation filters.
t
@Marvin I'd like to choose solution 2 (adding a tag). I can add it when calling
run_deployment
. But I guess here again I can't act on a tag not being present right? Is there no "expect_not" key?
m
thought for 185.8 seconds
You’re correct — there’s no expect_not (or any NOT/EXISTS) in automation triggers. Filters are positive-only. If you go with tags, the pattern that works is to require a positive tag that only top-level runs have. Practically, that means: - Ensure top-level runs include a tag like
top-level
- Ensure subflow runs do not include that tag - Make your automation require that tag Example trigger JSON (adding a tag requirement to your existing deployment scope):
Copy code
{
  "type": "event",
  "match": {
    "prefect.resource.id": "prefect.flow-run.*"
  },
  "match_related": [
    {
      "prefect.resource.id": [
        "prefect.deployment.<deployment1-id>",
        "prefect.deployment.<deployment2-id>"
      ],
      "prefect.resource.role": "deployment"
    },
    {
      "prefect.resource.id": "prefect.tag.top-level"
    }
  ],
  "after": [],
  "expect": [
    "prefect.flow-run.Completed",
    "prefect.flow-run.Cached"
  ],
  "for_each": [
    "prefect.resource.id"
  ],
  "posture": "Reactive",
  "threshold": 1,
  "within": 0
}
Important caveat with tags: - If subflows are launched with run_deployment against the same deployment as your top-level runs and that deployment has default tags, those tags will typically be included on subflow runs too. In that case, requiring a “top-level” tag won’t distinguish them. - If you can’t ensure a tag that is present only on top-level runs (e.g., by using a separate deployment for top-level, or by only adding the tag when creating the top-level run), this tag-based approach won’t reliably exclude subflows. What you can do: - If you can add tags only when calling run_deployment: add a “subflow” tag to child runs, but don’t rely on the absence of that tag in the trigger. Instead, arrange for top-level runs to include a distinct “top-level” tag (e.g., via a separate deployment for top-level runs or by explicitly adding tags when you create top-level runs). - If you cannot guarantee a top-level-only tag, use the custom-event approach from earlier; it’s the most reliable way to separate top-level from subflows today. Docs: Event triggers
t
@Marvin Can you give me an updated json based on my current version, to incorporate a match_related on the top-level tag?
m
thought for 39.9 seconds
Here’s your trigger updated to also require the
top-level
tag via match_related. Note the array form so both related conditions must be satisfied (deployment AND tag):
Copy code
{
  "type": "event",
  "match": {
    "prefect.resource.id": "prefect.flow-run.*"
  },
  "match_related": [
    {
      "prefect.resource.id": [
        "prefect.deployment.<deployment1-id>",
        "prefect.deployment.<deployment2-id>"
      ],
      "prefect.resource.role": "deployment"
    },
    {
      "prefect.resource.id": "prefect.tag.top-level"
    }
  ],
  "after": [],
  "expect": [
    "prefect.flow-run.Completed",
    "prefect.flow-run.Cached"
  ],
  "for_each": [
    "prefect.resource.id"
  ],
  "posture": "Reactive",
  "threshold": 1,
  "within": 0
}
Make sure your top-level runs include the
top-level
tag (and subflows do not).