<@ULVA73B9P> if i setup an automation that gets tr...
# ask-marvin
m
@Marvin if i setup an automation that gets triggered whenever a flow/deployment let's call it A gets triggered, and the action of the automation is to run another deployment B. now the case is that if A gets triggered twice at the same time, is there any way i can control the run of B to occur only once?
m
thought for 308.6 seconds
Yes — there are a couple good ways to make sure B runs only once when A fires twice at the same time (assuming Prefect 3.x): Primary (recommended): aggregate A’s events in the Automation - Configure your Automation trigger with a threshold + time window so simultaneous A events are collapsed into a single action. - Example (React posture, match on A, aggregate for 30s):
Copy code
{
  "name": "Run B when A starts (deduped)",
  "enabled": true,
  "trigger": {
    "type": "event",
    "posture": "Reactive",
    "expect": ["prefect.flow-run.Scheduled"],  // or Pending/Running based on your need
    "match": {
      "prefect.resource.id": "<deployment-A-id>"
    },
    "threshold": 1,
    "within": 30
  },
  "actions": [
    {
      "type": "run-deployment",
      "source": "selected",
      "deployment_id": "<deployment-B-id>"
    }
  ]
}
- Multiple A “Scheduled” events that arrive within 30 seconds cause a single “Run deployment B” action when the window closes. - Docs: Event triggers and Creating automations Complementary: limit B so duplicates are dropped or queued - Set a deployment-level concurrency limit on B to 1 and choose the collision strategy you prefer: - ENQUEUE: only one B runs; the rest wait in a queue - CANCEL_NEW: only one B runs; additional triggers are immediately canceled - You can set this when calling `deploy()`:
Copy code
from prefect.client.schemas.objects import ConcurrencyLimitConfig
from prefect import flow

@flow
def b():
    ...

b.deploy(
    name="B",
    concurrency_limit=ConcurrencyLimitConfig(
        limit=1,
        # choose one:
        # collision_strategy="ENQUEUE",
        # or
        # collision_strategy="CANCEL_NEW",
        grace_period_seconds=300
    ),
)
- Docs: Deployments (concurrency limiting) Advanced (if you need a global gate) - Use a global concurrency limit (name-based) to ensure only one B’s critical section runs at a time, regardless of trigger source:
Copy code
from prefect.concurrency.sync import concurrency
from prefect import flow

@flow
def b():
    with concurrency("run-b-once", occupy=1):
        # guarded work here
        ...
- Docs: Global concurrency limits Notes - The “Run deployment” action itself is idempotent only when the same idempotency key is reused; separate automation invocations won’t share a key by default. That’s why the threshold/within window is the best way to collapse duplicate triggers up front. Docs on run_deployment: Run deployments Quick check to tailor this: - Which state are you listening for on A (Scheduled, Pending, Running)? - Do you want extra triggers to be dropped, or queued to run later?
m
@Marvin now my question is to how can i only let any deployment run once at the same time, considering the deployment got triggered twice due to an event back to back within a fraction of seconds
m
thought for 26.5 seconds
Short answer: set a deployment-level concurrency limit of 1. That guarantees only one active run of that deployment at any moment, even if it’s triggered twice within milliseconds. Two behaviors to choose from when the second trigger arrives: - ENQUEUE (default): the second run waits until the current run finishes - CANCEL_NEW: the second run is immediately canceled (often preferred for “run once” semantics) How to set it UI - Go to Deployments → select your deployment → Settings/Concurrency - Max active runs: 1 - Collision strategy: choose ENQUEUE or CANCEL_NEW - Optionally adjust grace period Python (during deploy)
Copy code
from prefect import flow
from prefect.client.schemas.objects import ConcurrencyLimitConfig

@flow
def my_flow():
    ...

my_flow.deploy(
    name="my-deployment",
    concurrency_limit=ConcurrencyLimitConfig(
        limit=1,
        collision_strategy="CANCEL_NEW",   # or "ENQUEUE"
        grace_period_seconds=300           # optional
    ),
)
Notes - Using an integer shorthand like
concurrency_limit=1
defaults to ENQUEUE. If you want duplicates dropped, specify
CANCEL_NEW
. - This works regardless of why the deployment was triggered (manual, schedule, automation, API). - If you also want to collapse multiple events into a single action before creating extra runs, add a small “within” window on your Automation trigger; but deployment concurrency = 1 is the universal guardrail. Docs - Deployments (concurrency limiting): Deployments - Automations and event triggers (threshold/within): Event triggers Want me to suggest exact settings for your deployment(s) and whether to use ENQUEUE or CANCEL_NEW based on your workflow?
m
@Marvin what if both the runs got triggered exactly at the same time? will it let one of the flow run and cancel the other one or just cancel both or let run both?
m
thought for 22.2 seconds
With a deployment-level concurrency limit of 1, Prefect guarantees only one of those “simultaneous” runs will proceed: - ENQUEUE (default): one run acquires the slot and starts; the other goes to
AwaitingConcurrencySlot
and will run after the first finishes. - CANCEL_NEW: one run acquires the slot and starts; the other is immediately canceled. “Exactly at the same time” still resolves to one winner — the server serializes the slot claim in a transaction so they won’t both run. If you do not set a concurrency limit on the deployment, both runs will start. Optional extra protection: add a small
within
window on your Automation trigger to collapse back-to-back events into a single action, but the deployment concurrency limit is the definitive guardrail. Docs: - Deployment concurrency limits - Automation event triggers (threshold/within)