oleander-whirlwind
04/22/2026, 8:08 AMMarvin
04/22/2026, 8:09 AMMarvin
04/22/2026, 8:12 AMresources block for the container. Define variables for values you want to override later.
- Deployment (override per deployment)
- Set work_pool.job_variables in your prefect.yaml or in .deploy() to override the defaults for that specific deployment.
- Per run (one-off override)
- When triggering a run, pass --job-variable flags or set values in the UI run form.
Quick examples
1) Work pool base job template (add variables + reference them in the manifest)
{
"variables": {
"cpu_request": {
"type": "string",
"default": "100m"
},
"cpu_limit": {
"type": "string",
"default": "1000m"
},
"memory_request": {
"type": "string",
"default": "256Mi"
},
"memory_limit": {
"type": "string",
"default": "1Gi"
}
},
"job_configuration": {
"job_manifest": {
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "prefect-job",
"resources": {
"requests": {
"cpu": "{{ cpu_request }}",
"memory": "{{ memory_request }}"
},
"limits": {
"cpu": "{{ cpu_limit }}",
"memory": "{{ memory_limit }}"
}
}
}
]
}
}
}
}
}
}
Tip: If your current base template doesn’t include these variables yet, add them as shown and reference them with {{ variable_name }}.
2) Per-deployment override in prefect.yaml
deployments:
- name: my-deployment
entrypoint: flows/my_flow.py:my_flow
work_pool:
name: my-k8s-pool
job_variables:
cpu_request: "500m"
cpu_limit: "2"
memory_request: "512Mi"
memory_limit: "2Gi"
3) Per-deployment override in code
from prefect import flow
@flow
def my_flow():
...
flow.from_source(
source="<https://github.com/myorg/myrepo.git>",
entrypoint="flows/my_flow.py:my_flow"
).deploy(
name="my-deployment",
work_pool_name="my-k8s-pool",
job_variables={
"cpu_request": "500m",
"cpu_limit": "2",
"memory_request": "512Mi",
"memory_limit": "2Gi"
}
)
4) One-off override at run time (CLI)
prefect deployment run my-deployment \
--job-variable cpu_request=250m \
--job-variable memory_request=128Mi
Helpful commands and docs
- Show the default Kubernetes base job template (so you can copy/modify it):
prefect work-pool get-default-base-job-template --type kubernetes
- Customize base job templates: https://docs.prefect.io/v3/advanced/customize-base-job-templates
- Override job variables on deployments/runs: https://docs.prefect.io/v3/how-to-guides/deployments/customize-job-variables
- Run flows on Kubernetes (setup + worker): https://docs.prefect.io/v3/how-to-guides/deployment_infra/kubernetes
If you’d like, I can help you edit your current work pool template—just share whether you’re using the UI or CLI and what defaults you want.oleander-whirlwind
05/05/2026, 8:21 AMMarvin
05/05/2026, 8:21 AMMarvin
05/05/2026, 8:21 AMserve() is typically called on the flow object as flow.serve(...), not as a standalone function with just orchestration options.
* limit is not the same as a deployment concurrency_limit
* webserver=True is not part of the common flow.serve() signature in Prefect 3.x as far as I’d expect from the public API
* If you're using Prefect 3.x, the preferred deployment pattern is flow.from_source(...).deploy(...) or flow.deploy(...) depending on how you're packaging code
If you want to serve a flow locally with a concurrency limit, the shape is more like:
python
from prefect import flow
@flow
def apply_flow():
print("hello")
if __name__ == "__main__":
apply_flow.serve(
name="my-deployment",
limit=1,
pause_on_shutdown=False,
)
If instead you want to create a deployment object with a deployment-level concurrency limit, that is a different step from serving:
python
deployment = apply_flow.to_deployment(
name=args.deployment_name,
concurrency_limit=5,
)
Then you would typically serve that deployment or use a worker-based deployment approach depending on your setup.
So the main correction to your snippet is that this:
python
serve(
limit=1,
pause_on_shutdown=False,
webserver=True,
)
probably should be one of these two patterns:
Serve the flow directly:
python
apply_flow.serve(
name=args.deployment_name,
limit=1,
pause_on_shutdown=False,
)
Or build a deployment separately if you need deployment configuration:
python
deployment = apply_flow.to_deployment(
name=args.deployment_name,
concurrency_limit=5,
)
If you want, I can help rewrite your full snippet for either:
* local serve() style execution, or
* worker / deploy style execution in Prefect 3.xoleander-whirlwind
05/05/2026, 8:26 AMMarvin
05/05/2026, 8:26 AMMarvin
05/05/2026, 8:28 AMserve(...).
The key distinction is:
* flow.to_deployment(...) creates a RunnerDeployment
* prefect.serve(...) serves one or more RunnerDeployment objects
* you do not call .serve() on the deployment object itself
So your pattern should look like this:
python
from prefect import flow, serve
@flow
def apply_flow():
print("running")
deployment = apply_flow.to_deployment(
name=args.deployment_name,
concurrency_limit=5,
)
serve(
deployment,
limit=1,
pause_on_shutdown=False,
webserver=True,
)
A few notes:
* concurrency_limit=5 on to_deployment(...) is the deployment-level concurrency limit
* limit=1 on serve(...) is the runner-level limit for how many flow runs this serving process will execute concurrently
* pause_on_shutdown=False is valid on serve(...)
* webserver=True is supported here as well
So if your goal is:
1. create deployment separately
2. serve it with runner options
then this is the correct pattern.
If you want, I can help turn your exact snippet into a complete if __name__ == "__main__": example with CLI args included.oleander-whirlwind
05/05/2026, 9:05 AMMarvin
05/05/2026, 9:05 AMMarvin
05/05/2026, 9:07 AMconcurrency_limit you set in to_deployment(...).
Your log:
text
Concurrency lease renewal failed - slots are no longer reserved. Terminating execution to prevent over-allocation.
Crash detected! Execution was cancelled by the runtime environment.
Finished in state Crashed('Execution was cancelled by the runtime environment.')
means:
1. the run acquired a concurrency slot
2. Prefect tried to renew that slot lease in the background
3. renewal failed because the slot reservation no longer existed
4. Prefect cancelled the run on purpose
Common causes
* API connectivity issue: intermittent network issue between the serving process and Prefect API
* Server restart: if using self-hosted Prefect Server and it restarted, active leases may be lost
* Execution lasting past lease-renewal window with trouble renewing
* Known bug: there are open issues for this exact message, including retry / timeout related cases:
* Issue #20251
* Issue #19068
* Issue #18839
What I’d check first
1. Are you using self-hosted Prefect Server or Prefect Cloud?
* if self-hosted: check whether the API/server restarted around 11:04:38
2. Did the run sit in retry / timeout / long-running state?
* one reported bug is specifically around AwaitingRetry
3. Was there a network blip between your runner and API?
* especially if serving locally, in Docker, or in Kubernetes
4. What Prefect version are you on?
* if you're on an older 3.x patch, upgrading is a good idea
Most likely mitigation steps
* Upgrade Prefect to the latest 3.x patch release first
* If this is self-hosted, check API/server logs for restarts or connectivity issues
* If the issue started only after adding concurrency_limit=5, try temporarily removing the deployment concurrency limit and see whether the crash disappears
* If the run uses retries or long waits, compare against #20251
A good isolation test is:
python
deployment = apply_flow.to_deployment(
name=args.deployment_name,
# temporarily remove this
# concurrency_limit=5,
)
serve(
deployment,
limit=1,
pause_on_shutdown=False,
)
If the crashes stop, that strongly suggests the problem is specifically with the deployment concurrency lease path.
If you want, send me:
* your Prefect version (prefect version)
* whether you're on Cloud or self-hosted Server
* whether the flow has retries / timeout / long sleeps
* whether this started only after adding concurrency_limit
and I can help narrow down whether you're hitting infrastructure/connectivity vs a known Prefect bug.oleander-whirlwind
05/05/2026, 9:22 AMMarvin
05/05/2026, 9:22 AMMarvin
05/05/2026, 9:23 AMconcurrency_limit if that is what is triggering the lease-renewal crashes.
So in your case, yes, removing:
python
deployment = apply_flow.to_deployment(
name=args.deployment_name,
concurrency_limit=5,
)
is a reasonable workaround to test first.
Then serve it like:
python
deployment = apply_flow.to_deployment(
name=args.deployment_name,
)
serve(
deployment,
limit=1,
pause_on_shutdown=False,
webserver=True,
)
Important distinction:
* concurrency_limit on the deployment uses the lease-based concurrency mechanism that is producing your crash
* limit=1 on serve(...) limits how many runs that runner process executes concurrently, but it is not the same protection as a deployment concurrency limit across all infrastructure
So whether this workaround is acceptable depends on what you need:
If you have a single serving process only
* using serve(..., limit=1) may be enough as a temporary workaround
If you have multiple runners / workers / replicas
* removing deployment concurrency means you lose the shared central concurrency enforcement
* in that case, multiple processes could still run more flow runs than you want
So the preferred workaround order on 3.6.5 would be:
1. Remove deployment concurrency_limit
2. Keep serve(..., limit=...) if a single runner process is sufficient
3. If you need cluster-wide concurrency control, use an external lock / coordination mechanism in your flow logic until you can upgrade
4. Avoid long retry-wait patterns or timeouts combined with deployment concurrency if those are part of your runs
Recommended temporary pattern
python
from prefect import flow, serve
@flow
def apply_flow():
print("running")
if __name__ == "__main__":
deployment = apply_flow.to_deployment(
name="my-deployment",
)
serve(
deployment,
limit=1,
pause_on_shutdown=False,
webserver=True,
)
My recommendation
If stability is more important than strict central concurrency right now, then yes: remove deployment concurrency and rely on runner-local limit as the workaround.
If you want, I can also suggest a safe replacement strategy depending on whether you run:
* one local process
* multiple containers
* Kubernetes
* multiple replicas of the same serve processoleander-whirlwind
05/05/2026, 9:28 AMMarvin
05/05/2026, 9:28 AMMarvin
05/05/2026, 9:31 AM3.6.5
* The issue was still being reported on later versions like 3.6.8
* There were multiple incremental concurrency-related fixes after 3.6.5
* The main lease-renewal starvation fix in #21308 is definitely after 3.6.5
So for your practical question:
No, 3.6.5 does not contain the relevant fix
Yes, later 3.6.x releases include important concurrency lease fixes
If you cannot upgrade, the preferred workaround is still to avoid deployment concurrency_limit
Relevant links:
* PR #21308
* Issue #20251
* Issue #19068
* Issue #18839
* Latest release notes: Prefect releases
If you want, I can do one more pass and help infer the likely minimum 3.6.x version from the merge timing / changelog sequence, but I don’t want to overstate certainty without a direct release mapping.