This message was deleted.
# ask-community
s
This message was deleted.
m
thought for 408.4 seconds
Thanks for the details — I see the pain: with a Kubernetes work pool, each flow run becomes a separate Kubernetes Job/Pod, so even “do one HTTP call and finish” runs pay ~300MB per run. There are a few ways to reduce that overhead. Broadly, you can either (a) stop launching a new pod per run, or (b) keep using K8s jobs but make each pod lighter, or (c) do fewer flow runs by batching. Here are the main options and trade-offs: Option A — Reuse a single long‑lived pod (Process worker) - What it does: Run a Process worker in a single pod (e.g., as a Deployment) and point your deployments at a Process work pool. Each flow run executes as a subprocess inside that pod — no new pods per run. - Pros: Minimal per-run overhead; fast start times; great for simple I/O-bound jobs (HTTP calls). - Cons: Less isolation between runs; you can’t use per-run custom images. - How to set up: 1) Create a Process work pool:
Copy code
prefect work-pool create my-process-pool --type process
2) Run a worker inside your cluster (you can use the Prefect worker Helm chart or your own Deployment) to poll this pool:
Copy code
prefect worker start -p my-process-pool --name k8s-process-worker-1
Example Deployment snippet:
Copy code
apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: prefect-process-worker
     spec:
       replicas: 1
       selector:
         matchLabels:
           app: prefect-process-worker
       template:
         metadata:
           labels:
             app: prefect-process-worker
         spec:
           containers:
             - name: worker
               image: prefecthq/prefect:3-latest
               args: ["prefect","worker","start","-p","my-process-pool","--name","k8s-process-worker-1"]
               env:
                 - name: PREFECT_API_URL
                   value: "<http://prefect-server-api.prefect.svc.cluster.local:4200/api>"
               resources:
                 requests:
                   cpu: "100m"
                   memory: "128Mi"
                 limits:
                   cpu: "1"
                   memory: "512Mi"
3) Point your deployments to the Process pool (no per-run pod creation). For example, in Python:
Copy code
from prefect import flow

     @flow
     def my_flow():
         ...

     if __name__ == "__main__":
         my_flow.deploy(
             name="prod",
             work_pool_name="my-process-pool",
         )
- Docs: - Prefect docs - Work pools and workers: https://docs.prefect.io/latest/concepts/work-pools-workers/ - Process infrastructure: https://docs.prefect.io/latest/deploy/infrastructure/process/ Option B — Keep Kubernetes jobs, but make each pod smaller - Use a smaller base image (e.g., a Python slim image + install Prefect at build time) and minimize layers. - Lower memory requests/limits in your Kubernetes work pool’s base job template. - Get the default template to edit:
Copy code
prefect work-pool get-default-base-job-template --type kubernetes > k8s-template.json
- Update your work pool with the edited template, then set leaner
job_variables
on deployments (image, env, resources). - This reduces per-pod memory but you’ll still incur one pod per run. - Docs: - Kubernetes deployment/infrastructure: https://docs.prefect.io/latest/deploy/infrastructure/kubernetes/ Option C — Fewer flow runs: batch many HTTP calls per run - If you currently kick off one flow run per HTTP call, consider running one flow that triggers many requests concurrently. - Use a task runner to fan out I/O-bound calls: ``` from prefect import flow, task from prefect.task_runners import ThreadPoolTaskRunner import httpx @task def fetch(url: str) -> int: r = httpx.get(url, timeout=60.0) return r.status_code @flow(task_runner=ThreadPoolTaskRunner(max_workers=32)) def batch_fetch(urls: list[str]):
results = [fetch.submit(u) for u in urls] return [r.result() for r in results]
Copy code
- Control global or per-endpoint concurrency with Prefect concurrency limits (tag your tasks and create limits):
# tag your task with tags=["external-api"] prefect concurrency-limit create external-api 10 ``` - Docs: - Task runners: https://docs.prefect.io/latest/concepts/task-runners/ - Concurrency limits: https://docs.prefect.io/latest/concepts/concurrency/ - CLI reference (concurrency): https://docs.prefect.io/latest/reference/cli/ Quick recommendations based on your description - If isolation and per-run images are not required: switch to a Process work pool with a single long‑lived worker pod (Option A). This is the biggest win for your use case and usually cuts RAM overhead per run to near-zero beyond the worker’s baseline. - If you must keep per-run K8s jobs: trim the image and resource requests/limits (Option B), and consider batching to reduce the number of runs (Option C). A couple of sanity checks we ran on the CLI - Work pool create/help: -
prefect work-pool create --help
(supports
--type kubernetes|docker|process
) - Concurrency limit commands: -
prefect concurrency-limit --help
(supports create/ls/inspect/delete/reset) Questions to help us steer you to the best setup - Are you okay trading per-run pod isolation for much lower overhead (i.e., run a Process worker in one pod)? - Roughly how many runs per hour/day and how long does each HTTP request take? - Do you need per-run custom container images? - Are you on Prefect 3.x? (I’ve assumed 3.x here.) If you share those constraints, I can provide a concrete Helm values.yaml (for a Process worker) or a tuned Kubernetes job template for your current pool.