Shubham
06/30/2026, 1:46 PMMarvin
06/30/2026, 1:46 PMMarvin
06/30/2026, 1:48 PMrun_deployment()
from prefect.deployments import run_deployment
flow_run = run_deployment(
name="my-flow/my-deployment",
parameters={"x": 1},
timeout=None, # wait until finished
)
result = flow_run.state.result()
print(result)
If the deployment completes successfully, result is the flow's return value.
Async version:
from prefect.deployments import arun_deployment
flow_run = await arun_deployment(
name="my-flow/my-deployment",
parameters={"x": 1},
timeout=None,
)
result = await flow_run.state.aresult()
print(result)
Important limitation
If you trigger a deployment through the raw REST API or lower-level client, the initial response only gives you the flow run metadata — not the final return value. You must:
1. create the flow run
2. poll until it reaches a final state
3. fetch the result from the state
Example with the client:
import asyncio
from prefect import get_client
async def run_and_get_result(deployment_id):
async with get_client() as client:
flow_run = await client.create_flow_run_from_deployment(
deployment_id=deployment_id,
parameters={"x": 1},
)
while True:
flow_run = await client.read_flow_run(flow_run.id)
if flow_run.state.is_final():
break
await asyncio.sleep(2)
return await flow_run.state.aresult()
A few gotchas:
- The flow’s return value must be serializable / storable as a Prefect result.
- If the flow fails, state.result() / state.aresult() can raise the underlying exception.
- timeout=0 returns immediately, so you won’t have the final output yet.
If you want, I can give you:
- a FastAPI example that exposes “run deployment and return result”
- a curl/REST polling example
- or a pattern for large outputs (store artifact/object and return a reference)Shubham
06/30/2026, 1:53 PMShubham
06/30/2026, 1:53 PMMarvin
06/30/2026, 1:53 PMMarvin
06/30/2026, 1:56 PMPOST /deployments/{deployment_id}/create_flow_run
2. returns a flow_run_id
3. you poll GET /flow_runs/{flow_run_id}
4. once state is final, read the result
So the pattern is:
POST /deployments/{deployment_id}/create_flow_run
-> returns flow_run_id
then:
GET /flow_runs/{flow_run_id}
until state.type is one of:
- COMPLETED
- FAILED
- CRASHED
- CANCELLED
Then inspect the state/result.
Important: there is no built-in single HTTP endpoint in Prefect Cloud/Server that blocks until execution completes and then returns the flow’s return value in the same HTTP response.
If you want that behavior, you should build a wrapper service around Prefect.
Best option if you want one HTTP request that waits and returns the result
Create your own API endpoint that calls Prefect’s Python SDK run_deployment() and waits.
Example:
from fastapi import FastAPI, HTTPException
from prefect.deployments import run_deployment
app = FastAPI()
@app.post("/run")
def run_flow(payload: dict):
flow_run = run_deployment(
name="my-flow/my-deployment",
parameters=payload,
timeout=None, # wait until done
poll_interval=2
)
state = flow_run.state
if state.is_completed():
return {"flow_run_id": str(flow_run.id), "result": state.result()}
if state.is_failed() or state.is_crashed() or state.is_cancelled():
raise HTTPException(status_code=500, detail=str(state))
return {"flow_run_id": str(flow_run.id), "state": str(state.type)}
That gives your caller a synchronous HTTP experience, while Prefect still runs the deployment remotely.
If you must use only raw HTTP against Prefect API
Then implement polling yourself.
Example polling flow:
import time
import requests
PREFECT_API = "<https://api.prefect.cloud/api/accounts/.../workspaces/...>"
API_KEY = "YOUR_API_KEY"
DEPLOYMENT_ID = "YOUR_DEPLOYMENT_ID"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# Start flow run
resp = <http://requests.post|requests.post>(
f"{PREFECT_API}/deployments/{DEPLOYMENT_ID}/create_flow_run",
headers=headers,
json={"parameters": {"x": 1}},
)
resp.raise_for_status()
flow_run = resp.json()
flow_run_id = flow_run["id"]
# Poll
while True:
r = requests.get(
f"{PREFECT_API}/flow_runs/{flow_run_id}",
headers=headers,
)
r.raise_for_status()
flow_run = r.json()
state = flow_run["state"]
state_type = state["type"]
if state_type in ["COMPLETED", "FAILED", "CRASHED", "CANCELLED"]:
print(flow_run)
break
time.sleep(2)
One caveat on results
The flow return value is not always ideal to fetch directly via plain raw HTTP, especially for larger or persisted results. In Python, state.result() is the most reliable way because it knows how to resolve persisted results from storage.
So in practice:
- Need simple synchronous request/response? Use your own API + run_deployment()
- Need pure Prefect HTTP API? Use create_flow_run + poll flow_runs/{id}
- Need large outputs? Better to store the result externally and return a reference/URL/id
Useful references:
- Prefect deployment triggering/result handling is exposed in the Python SDK via run_deployment() / arun_deployment()
- Prefect API concepts: https://docs.prefect.io/
- Python SDK reference: https://docs.prefect.io/v3/api-ref/python/prefect-deployments-flow_runs
If you want, I can give you a complete FastAPI wrapper or Node.js polling example.Shubham
06/30/2026, 2:06 PMMarvin
06/30/2026, 2:06 PMMarvin
06/30/2026, 2:07 PMprefect.db for SQLite, or your Postgres DB if using Postgres)
This stores:
- flow runs
- task runs
- state history
- logs
- events
- artifacts metadata
For frequent runs, events and logs grow very fast.
2. Persisted results
If you enable result persistence, returned flow/task data is stored somewhere.
In local/on-prem setups, this is often under Prefect home storage, commonly:
- ~/.prefect/storage/
If the flow returns large payloads every 5 min, this can grow quickly.
3. Logs
Verbose logging from tasks and flows can make the DB much larger over time.
Default important locations
- Prefect home: ~/.prefect/
- SQLite DB default: ~/.prefect/prefect.db
- Local result storage default: ~/.prefect/storage/
So if you are using defaults, the main files/directories to monitor are:
~/.prefect/prefect.db
~/.prefect/storage/
For your case: every 5 minutes
That means:
- 12 runs/hour
- 288 runs/day
- 8,640 runs/month
If each run persists results and writes logs, storage can grow fast.
Best practices to keep on-prem healthy
1. Use PostgreSQL for production
Do not rely on SQLite for a busy on-prem server.
Use:
- PostgreSQL for Prefect API database
- external object storage for results if possible
2. Do not persist large results locally unless needed
If you only need results for a short time, either:
- avoid persistence when possible
- store only small summaries
- write full outputs to S3 / MinIO / shared object storage instead
3. Enable database cleanup / vacuum services
Prefect has DB vacuum services for old data cleanup.
Recommended settings for a high-frequency environment:
PREFECT_SERVER_SERVICES_DB_VACUUM_ENABLED=events,flow_runs
PREFECT_EVENTS_RETENTION_PERIOD=2d
PREFECT_SERVER_SERVICES_DB_VACUUM_RETENTION_PERIOD=7d
That means:
- events older than 2 days cleaned up
- old flow/task run records cleaned after 7 days
4. Keep result retention short
If you persist results, set a cleanup policy yourself.
Prefect won’t magically manage your local result files forever unless your storage lifecycle handles it.
If using local filesystem storage, you may need a cron job to remove old files.
5. Reduce log volume
Avoid excessive <http://logger.info|logger.info>() in loops or large object dumps.
6. Monitor disk regularly
Check:
du -sh ~/.prefect/*
and for DB size:
ls -lh ~/.prefect/prefect.db
or for Postgres, monitor DB/table sizes directly.
Recommended architecture for your use case
If deployments run every 5 min and results matter:
- Prefect server DB: PostgreSQL
- Result storage: S3 / MinIO / network object storage
- Vacuum enabled: yes
- Short retention: yes
- Local disk: only for temporary server files, not long-term results
Practical rule of thumb
- Biggest file if using SQLite: ~/.prefect/prefect.db
- Biggest directory if persisting results locally: ~/.prefect/storage/
What I’d recommend for on-prem
If this is production-like:
1. move from SQLite to Postgres
2. store persisted results outside the server disk
3. enable Prefect DB vacuum
4. set short retention for events/runs
5. add OS-level monitoring for disk + memory + DB growth
Useful docs:
- Database maintenance
- Self-hosted Prefect
If you want, I can give you a sample docker-compose setup for on-prem Prefect with Postgres + MinIO + retention settings.Shubham
06/30/2026, 2:23 PMMarvin
06/30/2026, 2:23 PMMarvin
06/30/2026, 2:26 PMimage in job_variables, the worker uses that image when creating the infrastructure job.
But who actually pulls the image depends on the worker type.
Docker worker
For a Docker work pool / Docker worker:
- Prefect worker reads the deployment job variables
- sees image=...
- uses the Docker API on the worker host
- Docker pulls the image if needed
- then starts the container from that image
So for Docker workers, the pull is effectively done through the worker via Docker, on the machine where the worker is running.
If the image is private, you usually provide registry credentials.
Typical deployment override:
job_variables={
"image": "my-registry/my-image:1.2.3"
}
For private registries with Docker worker, you may also need registry credentials in the work pool / deployment config.
Kubernetes worker
For a Kubernetes work pool / Kubernetes worker:
- Prefect worker creates a Kubernetes Job manifest
- the manifest includes the image
- Kubernetes pulls the image on the cluster node
So in this case, Prefect does not pull the image itself.
Kubernetes does.
If the image is private, you need Kubernetes imagePullSecrets.
Example conceptually:
job_variables={
"image": "my-registry/my-image:1.2.3",
"image_pull_secrets": ["my-registry-secret"]
}
Important rule
job_variables on the deployment override the work pool defaults.
So if your work pool default image is:
prefecthq/prefect:3-latest
and the deployment has:
job_variables={
"image": "custom/app:5"
}
then the worker will use custom/app:5 for that deployment run.
What machine needs network access?
Depends on worker type:
- Docker worker: the worker host must be able to reach the registry
- Kubernetes worker: the Kubernetes nodes must be able to reach the registry
What about pull policy?
Usually controlled by something like image_pull_policy.
Common behavior:
- Always → always pull
- IfNotPresent → pull only if missing
- Docker worker may auto-decide based on tag like latest
In short
- job_variables["image"] tells Prefect what image to run
- Docker worker: Docker on the worker host pulls it
- Kubernetes worker: Kubernetes pulls it
- for private images, configure the proper credentials for that infrastructure
- deployment job_variables override work pool defaults
Docs:
- Work pools and workers
- Docker deployment infrastructure
- Kubernetes deployment infrastructure
If you want, I can show you the exact configuration for:
- Docker worker + private registry
- Kubernetes worker + imagePullSecrets
- or prefect.yaml job_variables exampleShubham
06/30/2026, 2:29 PMMarvin
06/30/2026, 2:29 PMMarvin
06/30/2026, 2:31 PMapi.prefect.cloud
- app.prefect.cloud (not needed by the worker itself, but useful for human UI access)
- <http://auth.workos.com|auth.workos.com> (mainly for browser/user auth; worker itself primarily needs API access)
For the worker itself, the critical one is:
- api.prefect.cloud:443
That is used for:
- polling work from the work pool
- creating/updating flow run state
- sending logs/events
- worker heartbeats
If using self-hosted Prefect Server
Allow outbound HTTPS to your Prefect API URL, for example:
- prefect.mycompany.internal:443
or wherever your PREFECT_API_URL points.
The worker mainly needs access to:
- your configured PREFECT_API_URL
Also whitelist image registry endpoints
Since this is a Docker worker, it also needs outbound access to wherever the image is pulled from.
Examples:
- Docker Hub: <http://registry-1.docker.io|registry-1.docker.io>
- GitHub Container Registry: <http://ghcr.io|ghcr.io>
- AWS ECR: <account>.dkr.ecr.<region>.<http://amazonaws.com|amazonaws.com>
- Azure ACR: <registry>.<http://azurecr.io|azurecr.io>
- GCP Artifact Registry: <region>-docker.pkg.dev
If your deployment image is private, also allow the auth flow for that registry as needed.
If your code or results use external storage, whitelist those too
Common extras:
- GitHub source code: <http://github.com|github.com>, <http://api.github.com|api.github.com>
- S3: <http://s3.amazonaws.com|s3.amazonaws.com> or regional S3 endpoint
- GCS: <http://storage.googleapis.com|storage.googleapis.com>
- Azure Blob: <account>.<http://blob.core.windows.net|blob.core.windows.net>
- private package index / PyPI: <http://pypi.org|pypi.org>, <http://files.pythonhosted.org|files.pythonhosted.org>
So the real allowlist depends on:
- where Prefect API is
- where Docker images are hosted
- where flow code is fetched from
- where results/artifacts are stored
Practical minimums
Prefect Cloud + Docker Hub image
api.prefect.cloud:443
<http://registry-1.docker.io:443|registry-1.docker.io:443>
<http://auth.docker.io:443|auth.docker.io:443>
<http://production.cloudflare.docker.com:443|production.cloudflare.docker.com:443>
Self-hosted Prefect + private registry
<your-prefect-api-host>:443
<your-registry-host>:443
Recommended checklist
Your Docker worker host should be able to reach:
1. Prefect API
2. container registry
3. code storage if using remote source
4. result storage if persisting results remotely
5. package repositories if installing dependencies at runtime
Notes
- Use DNS/domain allowlisting, not static IPs, especially for Prefect Cloud
- Websocket/long-poll behavior is still over standard HTTPS/WSS, usually port 443
- If you use a corporate proxy, set HTTPS_PROXY / HTTP_PROXY
You can verify the configured API target with:
prefect config view
Docs:
- Workers
- Work pools
- Self-hosted Prefect
If you want, I can give you a precise firewall allowlist table for your setup if you tell me:
- Prefect Cloud or self-hosted
- Docker Hub / ECR / ACR / GHCR
- Git-based source or baked-in image
- S3/GCS/Azure/local resultsShubham
06/30/2026, 2:37 PMMarvin
06/30/2026, 2:37 PMMarvin
06/30/2026, 2:37 PMprefect.mycompany.internal:443
This is whatever PREFECT_API_URL points to.
- GitHub
- <http://github.com:443|github.com:443>
- <http://api.github.com:443|api.github.com:443>
Needed if your deployment pulls code from GitHub.
- Docker Hub
- <http://registry-1.docker.io:443|registry-1.docker.io:443>
- <http://auth.docker.io:443|auth.docker.io:443>
- <http://production.cloudflare.docker.com:443|production.cloudflare.docker.com:443>
Needed to pull Docker images.
- Supabase
- <your-project>.<http://supabase.co:443|supabase.co:443>
Needed because your flow writes results to Supabase via API.
Possibly required depending on your GitHub auth method
If you clone private GitHub repos or use release/archive downloads, also allow:
- <http://codeload.github.com:443|codeload.github.com:443>
Optional but common
- <http://pypi.org:443|pypi.org:443>
- <http://files.pythonhosted.org:443|files.pythonhosted.org:443>
Only needed if your container installs packages at runtime.
Optional Prefect telemetry
If you want to disable extra telemetry/noise:
- set DO_NOT_TRACK=1
- set PREFECT_SERVER_ANALYTICS_ENABLED=false
That can reduce calls to telemetry endpoints.
Recommended allowlist for your case
<your-prefect-api-host>:443
<http://github.com:443|github.com:443>
<http://api.github.com:443|api.github.com:443>
<http://codeload.github.com:443|codeload.github.com:443>
<http://registry-1.docker.io:443|registry-1.docker.io:443>
<http://auth.docker.io:443|auth.docker.io:443>
<http://production.cloudflare.docker.com:443|production.cloudflare.docker.com:443>
<your-project>.<http://supabase.co:443|supabase.co:443>
Important note
Because you're self-hosted, the worker does not need api.prefect.cloud unless you are also using Prefect Cloud somewhere else.
If GitHub repo is private
You also need credentials/token handling inside the worker/container, but network-wise the above hosts are the key ones.
Best practice
Allow by domain name rather than fixed IPs, especially for:
- GitHub
- Docker Hub
- Supabase
Their IPs can change.
Quick connectivity checks from the worker host
curl -I <https://github.com>
curl -I <https://api.github.com>
curl -I <https://registry-1.docker.io/v2/>
curl -I https://<your-project>.<http://supabase.co|supabase.co>
curl -I https://<your-prefect-api-host>/api/health
If you want, I can turn this into:
- a network/firewall checklist
- a Docker worker readiness script
- or a minimal outbound policy document for your infra teamBring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by