Robert Szomolanyi
02/26/2026, 4:20 PMMarvin
02/26/2026, 4:20 PMMarvin
02/26/2026, 4:24 PMPREFECT_MESSAGING_BROKER and PREFECT_MESSAGING_CACHE to the Redis-backed implementations
- Concurrency leases: PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE=prefect_redis.lease_storage
- Event ordering: PREFECT_SERVER_EVENTS_CAUSAL_ORDERING=prefect_redis.ordering
- Docket (background services coordination): PREFECT_SERVER_DOCKET_URL=redis://...
- Database must be PostgreSQL
Notes for your two-cluster setup:
- Active-passive: keep only one Prefect Server running at a time (don’t run both background services). Point workers in both clusters to the active API URL. No Redis needed.
- Active-active: run multiple API pods (with --no-services) behind a load balancer and one separate background-services pod. Both clusters must reach the same PostgreSQL and Redis backends to avoid split-brain.
Useful docs
- Self-hosted scaling/HA overview: Scale self‑hosted Prefect (HA)
- Settings reference (DB, messaging, concurrency, docket): Settings reference
- Workers overview (multi-host scaling): Workers concepts
If you can share whether you want active-active or active-passive between your OpenShift clusters, I can provide exact env vars/manifests for that pattern.Yu(Irene) Chen
02/26/2026, 4:54 PMMarvin
02/26/2026, 4:54 PMresearch_prefect_topic
📊 Tools used:
• read_github_issues (1x)
• research_prefect_topic (1x)Yu(Irene) Chen
02/26/2026, 5:27 PMMarvin
02/26/2026, 5:27 PMMarvin
02/26/2026, 5:29 PMfrom prefect.client.orchestration import get_client
from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterTags
async def find_duplicate_schedules():
async with get_client() as client:
# scope if you like, e.g. by tag
deployments = await client.read_deployments(
deployment_filter=DeploymentFilter() # or add filters
)
dep_ids = [d.id for d in deployments]
runs = await client.get_scheduled_flow_runs_for_deployments(dep_ids)
# group by (deployment_id, expected_start_time) or just expected_start_time
seen = {}
dups = []
for r in runs:
key = (r.deployment_id, r.expected_start_time)
if key in seen:
dups.append((r.deployment_id, r.expected_start_time, r.id))
else:
seen[key] = r.id
return dups
If you share:
- Your Prefect version (server and workers)
- Whether you recently upgraded or changed schedules
- Whether you run multiple API/background-services instances
…I can suggest the safest path (upgrade target, a precise cleanup/toggle script, or deployment recreation steps) to stop the double runs.
References
- 3.0.0: Scheduled runs not deleted with deployment
- 3.2.x: Double runs after upgrade
- 3.4.15: Intermittent duplicate schedulesYu(Irene) Chen
02/27/2026, 6:30 AMMarvin
02/27/2026, 6:30 AMMarvin
02/27/2026, 6:32 AMreturn [t1.submit(), t2.submit()] from a flow.
- The engine blocks until those futures finish, replaces them with their terminal States, and sets the flow to COMPLETED only if all are completed; otherwise the flow fails.
- Results are persisted if your result settings enable it; the flow state’s result will contain the resolved structure.
Only exception
- If you deliberately wrap a future with quote(...), Prefect will not resolve it and will return the future object as-is.
If you want, I can share a minimal example that demonstrates the final flow state and result content for a list of futures.