List icon
Request icon
OutputValues icon
Log icon
If icon
Pause icon
Loop icon
Kill icon
LoopUntil icon
Fail icon
Assert icon
Exit icon
Schedule icon

Collapse Duplicate Queued Runs Behind a Kestra Concurrency Limit

Kill duplicate QUEUED Kestra executions piled up behind a concurrency limit, keep one run per input set, and label each killed run with the one it duplicated.

Categories
Infrastructure

A flow with concurrency.behavior: QUEUE queues every new run while its slot is busy. If one run hangs for two hours, a 5-minute schedule queues 24 identical runs. When the slot frees up, all 24 run one after another: a sync job does the same work 24 times, and a report is sent 24 times. This flow keeps one of them.

How it works

  1. Flows opt in with the label queue-policy: deduplicate. Only these flows are touched.
  2. The Kestra plugin lists the flows of namespace, and the API returns its queued executions (oldest first) and running ones.
  3. Queued runs of a flow are grouped by inputs, trigger payload, execution labels and replay origin, with JSON key order ignored. A Schedule's own dates and webhook headers are ignored, so scheduled runs count as the same work, while different webhook bodies, Flow-trigger payloads, labels or replayed executions stay apart. Each group keeps its oldest run, the one Kestra starts next, and the rest are duplicates.
  4. With dry_run: false, a Loop handles one duplicate at a time, newest first. It re-reads the duplicate and the run it duplicates, and kills the duplicate with the Kestra plugin only if it is still QUEUED and the kept run still exists and is queued, running or successful. It waits for KILLED, then adds the labels queue-duplicate-of: <kept run> and queue-collapse-run: <this run>, keeping the other labels. Otherwise the duplicate is left in place and logged with the reason.
  5. Afterwards the run counts the duplicates it actually killed. It ends SUCCESS only if every planned duplicate was killed, and WARNING with the remaining ids otherwise. A final query also checks that no duplicate is still queued next to a live kept run.

The kill is deliberate. Kestra frees no concurrency slot for a run killed while queued, but a queued run moved to CANCELLED through the unqueue API releases a slot it never held, and another run then starts next to the running one. A kill still has a short race: a duplicate can start between the re-check and the kill. That run is then killed while running, and the collapse fails and names it. The race is detected, not prevented.

What you get

  • A report per flow: queued runs, distinct input sets, duplicates, and the running execution that holds the slot.
  • One queued run per flow and input set, the concurrency limit intact, and a repeat run that changes nothing.
  • Audit labels on every killed run, and a WARNING or FAILED run whenever the collapse was partial or raced.

Who it's for

Platform teams running frequent schedules with concurrency limits, such as syncs, refreshes and exports.

Why orchestrate this with Kestra

It reads the same execution queue Kestra runs from, and the approval, bounded loop, retries and history are built in.

Prerequisites

  • Kestra 2.x and an API user that can read flows and executions, kill executions and set labels.
  • The Kestra plugin.

Secrets

  • KESTRA_USERNAME: user for basic auth against the Kestra API (required).
  • KESTRA_PASSWORD: password of that user (required).

Quick start

  1. Add the secrets and set kestra_url and namespace.
  2. Label flows whose identical queued runs are redundant with queue-policy: deduplicate.
  3. Run once with dry_run: true and read the report.
  4. Enable the 15-minute schedule. Runs that would kill more than approval_above executions wait for approval.

How to extend

  • Add one schedule per namespace, or pair it with a reaper for runs stuck in RUNNING.
  • Alert when one flow keeps building a backlog.

Do not opt in flows where each scheduled run handles its own date, such as partitioned loads.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.