Joseph Wibowo
11/25/2025, 2:30 AMMarvin
11/25/2025, 2:30 AMMarvin
11/25/2025, 2:40 AM{
"database_url": {
"value": "<postgresql://prod-db:5432/app>",
"tags": [
"database",
"prod"
]
},
"api_timeout": {
"value": 30,
"tags": [
"api"
]
},
"feature_flags": {
"value": {
"use_new_pipeline": true
}
}
}
Example concurrency-limits.yaml
tag_limits:
- { tag: "database", limit: 10 }
- { tag: "third_party_api", limit: 5 }
global_limits:
- { name: "api_calls", limit: 5, slot_decay_per_second: 2.0, active: true }
- { name: "big_query_pool", limit: 20, active: true }
2) Apply via CI (idempotent)
- Use the CLI for simplicity, or the Python client for more control.
- Verified CLI:
- Variables: prefect variable set|get|ls|inspect|delete
- Tag limits: prefect concurrency-limit create|ls|inspect|reset|delete
- Global limits: prefect gcl create|ls|inspect|update|enable|disable|delete
Sample GitHub Actions steps
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install prefect
- name: Apply variables
env:
PREFECT_API_URL: ${{ secrets.PREFECT_API_URL }}
PREFECT_API_KEY: ${{ secrets.PREFECT_API_KEY }}
run: python scripts/apply_variables.py config/variables.json
- name: Apply concurrency limits
env:
PREFECT_API_URL: ${{ secrets.PREFECT_API_URL }}
PREFECT_API_KEY: ${{ secrets.PREFECT_API_KEY }}
run: python scripts/apply_limits.py config/concurrency-limits.yaml
scripts/apply_variables.py (idempotent)
import json
from prefect.variables import Variable
import sys
path = sys.argv[1]
with open(path) as f:
spec = json.load(f)
for name, cfg in spec.items():
value = cfg["value"]
tags = cfg.get("tags", [])
Variable.set(name=name, value=value, tags=tags, overwrite=True)
print(f"✓ set {name}")
scripts/apply_limits.py (idempotent)
```
import sys, yaml, asyncio
from prefect import get_client
from prefect.client.schemas.actions import GlobalConcurrencyLimitCreate, GlobalConcurrencyLimitUpdate
path = sys.argv[1]
async def main():
with open(path) as f:
spec = yaml.safe_load(f)
async with get_client() as client:
# tag-based (task) limits
for item in spec.get("tag_limits", []):
tag = item["tag"]; limit = int(item["limit"])
try:
existing = await client.read_concurrency_limit_by_tag(tag)
if existing.concurrency_limit != limit:
await client.update_concurrency_limit_by_tag(tag, limit)Marvin
11/25/2025, 2:40 AM3) Track what exists (audit and drift)
- List variables
prefect variable ls --limit 1000
prefect variable inspect <name> --output json
- List concurrency limits
prefect concurrency-limit ls
prefect gcl ls
- Export snapshot (for backup/diff in CI)
python - <<'PY'
import asyncio, json
from prefect import get_client
async def export():
async with get_client() as client:
vars = await client.read_variables(limit=10000)
print(json.dumps({v.name: {"value": v.value, "tags": v.tags} for v in vars}, indent=2))
asyncio.run(export())
PY
```
You can commit snapshots or push to object storage, then compare them against your manifests for drift and alert in CI.
Notes and best practices
- Versioning: Prefect Variables are mutable and do not keep history. Git is your source of truth—review changes via PRs. If you need “versioned values,” encode the version in the name (e.g., my_config_v2) or keep version metadata inside the value.
- Secrets: Prefer Prefect Secret blocks or your cloud secret manager. Variables are not designed for secret-at-rest guarantees. See: prefect.blocks.system.Secret.
- Tag-based vs Global concurrency:
- Tag-based limits control how many tasks with a tag can run concurrently; add tags=[...] on tasks.
- Global limits work anywhere in code via context managers and support rate limiting with slot decay.
- In recent Prefect 3 releases, tag-based limits are backed by global limits named tag:{tag}.
- Namespacing: Prefix variable and limit names with env/team (e.g., prod_api_timeout, teamx_api_calls) to avoid collisions across workspaces/environments.
- Also consider execution-level limits:
- Work pool concurrency (cap total running flow runs per pool) and deployment concurrency (cap per-deployment). Those are configured separately if you need them.
If you share whether you’re on Prefect Cloud or self-hosted and how many environments you manage, I can tailor manifests and CI examples (GitHub Actions/GitLab/Argo) to your setup and include drift checks.