<@ULVA73B9P> I observe a delay of 1 minute approximatively to launch my Prefect flow with a Google C...
f
@Marvin I observe a delay of 1 minute approximatively to launch my Prefect flow with a Google Cloud Run Push worker. Is it possible to reduce this time? Or do I have to use another worker type?
m
thought for 384.6 seconds
Short answer: that ~1 minute is expected with Cloud Run “push” work pools in Prefect 2. It’s mostly Cloud Run Jobs cold start (image pull + job provisioning) and can’t be eliminated entirely. If you need consistently faster starts, switch to a pull-based worker running on always-on compute (e.g., a small GCE VM). Why it happens - Cloud Run Jobs are provisioned on-demand for each flow run, so there’s an unavoidable cold start. 30–90 seconds is common depending on image size, registry/region, and GCP scheduling. - Prefect’s overhead here is small compared to Cloud Run’s job startup. What you can do to reduce it (within Cloud Run) - Use the Cloud Run V2 worker (slightly better behavior vs v1 in many regions): CloudRunWorkerV2 code - Minimize your image: - Base on a slim image and bake all deps at build time (avoid pip installs on start) - Keep layers small and pinned - Keep everything regional: - Store the image in Artifact Registry in the same region as the job - Ensure the job’s service account has Artifact Registry Reader to avoid auth retries - Avoid optional features that add provisioning time unless needed (VPC connectors, large memory, etc.) But if you need much faster starts - Process worker on a small GCE VM (pull work pool): startup typically <1s. You’ll run
prefect worker start
as a system service on an always-on instance. - Docker worker on a GCE VM: 2–10s when the image is already pulled. - Kubernetes worker (GKE): 10–30s to schedule a pod and start the container. References - Prefect GCP Cloud Run worker (v1): CloudRunWorker code - Prefect GCP Cloud Run worker (v2): CloudRunWorkerV2 code - GCP docs: Cloud Run Jobs overview: Cloud Run Jobs If you share: - How often your flows run (e.g., every minute vs hourly) - Your acceptable startup latency target - Whether you prefer fully serverless vs managing a tiny VM …I can recommend the best worker type and outline the setup.
f
@Marvin My project is on a Docker container in Artifact registry, I use Prefect 3 and Prefect cloud. Give me the best solution to have a startup time < 10 s
m
thought for 361.3 seconds
Got it — on Prefect 3 + Cloud, with your project already built into a Docker image in Artifact Registry, the most reliable way to get <10s startup is to switch from serverless “push” to a pull-based Docker worker running on an always-on GCE VM. That eliminates Cloud Run’s cold starts and, with the image pre-pulled, container launches are typically 2–5s. Recommended setup (Docker worker on a small GCE VM) - VM: a small, always-on GCE instance in the same region as your Artifact Registry (e2-small/e2-medium is usually fine) - Auth: configure Docker to pull from Artifact Registry (
gcloud auth configure-docker <region>-docker.pkg.dev
) - Pre-pull your flow image and keep it cached locally - Use a Docker work pool; start a worker on the VM; deploy your flow to that pool with image_pull_policy set to if_not_present or never Step-by-step 1) Create a Docker work pool (once)
Copy code
prefect work-pool create "gce-docker" --type docker
2) Optionally set the pool’s base job template to avoid pulls on every run - Fetch the template:
Copy code
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
- Edit docker-pool.json and set: - "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG" - "image_pull_policy": "if_not_present" (or "never" if you’ll always pre-pull) - Apply:
Copy code
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
3) On the VM, install requirements and pre-pull the image
Copy code
pip install "prefect[docker]"
gcloud auth configure-docker REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
4) Start a Prefect worker on the VM (as a service) - Minimal start:
Copy code
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
export PREFECT_API_KEY="<YOUR_API_KEY>"

prefect worker start -p "gce-docker" -n "gce-docker-1"
- Optional systemd unit:
Copy code
[Unit]
Description=Prefect Docker Worker
After=docker.service
Requires=docker.service

[Service]
Environment=PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>
Environment=PREFECT_API_KEY=<YOUR_API_KEY>
ExecStart=/usr/local/bin/prefect worker start -p gce-docker -n gce-docker-1
Restart=always

[Install]
WantedBy=multi-user.target
5) Deploy your flow to this pool using your existing image - If your image already contains the flow code at the right path:
Copy code
from prefect import Flow

flow = Flow.from_source(
    source=".",  # entrypoint path must exist inside the image
    entrypoint="app/flow.py:main_flow",
)

flow.deploy(
    name="prod",
    work_pool_name="gce-docker",
    image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
    build=False,  # image already built
    push=False,   # image already pushed
)
Tips to reliably hit <10s - Keep the image small and pre-pulled on the VM - Set image_pull_policy to if_not_present (or never if you manage pulls yourself) - Avoid runtime git clone or pip install in the container’s entrypoint - Keep VM and Artifact Registry in the same region - Use a fixed tag or digest to avoid unexpected pulls Alternative if you don’t need containers - Process worker on a GCE VM is the fastest (<1s), but only if you can install your code and deps on the VM directly (no Docker). For your current containerized setup, Docker worker is the best fit. If you want, I can tailor a systemd unit + Terraform snippet for the VM (with a MIG) and a minimal Dockerfile to keep launch times in the 2–5s range.
f
@Marvin How can I do the following recommendations ?
- Keep everything regional:
- Store the image in Artifact Registry in the same region as the job
- Ensure the job’s service account has Artifact Registry Reader to avoid auth retries
- Avoid optional features that add provisioning time unless needed (VPC connectors, large memory, etc.)
m
thought for 137.5 seconds
Great question — here’s how to apply each recommendation on Prefect 3 with a Cloud Run v2 work pool. 1) Keep everything regional a) Put your image in a regional Artifact Registry that matches your Cloud Run job region - Check existing repos:
Copy code
gcloud artifacts repositories list --location=REGION
- Create a regional repo (if needed):
Copy code
gcloud artifacts repositories create REPO \
  --repository-format=docker \
  --location=REGION \
  --description="Prefect images"
- Tag and push your image to the regional registry:
Copy code
docker tag IMAGE:TAG REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
docker push REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
Docs: Artifact Registry: Store Docker images b) Configure your Prefect Cloud Run v2 work pool to use that same region and image - Create or update a Cloud Run v2 work pool:
Copy code
prefect work-pool create "cr-v2" --type cloud-run-v2
# or update existing
prefect work-pool get-default-base-job-template --type cloud-run-v2 --file cr.json
- Edit cr.json “variables” to set region and image (and keep other settings minimal):
Copy code
{
  "variables": {
    "region": "REGION",
    "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
    "service_account_name": "<mailto:my-sa@PROJECT.iam.gserviceaccount.com|my-sa@PROJECT.iam.gserviceaccount.com>",
    "cpu": "1000m",
    "memory": "512Mi",
    "vpc_connector_name": null,      // leave null/omit unless you need it
    "max_retries": 0,
    "timeout": 600,
    "env": {}
  }
}
- Apply the template:
Copy code
prefect work-pool update "cr-v2" --base-job-template cr.json
Reference: CloudRunWorkerV2 variables and job template 2) Ensure the job’s service account has Artifact Registry Reader - Create a service account (or pick an existing one) to run the job:
Copy code
gcloud iam service-accounts create prefect-cr-sa \
  --display-name="Prefect Cloud Run Jobs"
- Grant Artifact Registry Reader at the repository level (preferred) or project level: Repository-level:
Copy code
gcloud artifacts repositories add-iam-policy-binding REPO \
  --location=REGION \
  --member="serviceAccount:prefect-cr-sa@PROJECT.iam.gserviceaccount.com" \
  --role="roles/artifactregistry.reader"
Project-level (broader):
Copy code
gcloud projects add-iam-policy-binding PROJECT \
  --member="serviceAccount:prefect-cr-sa@PROJECT.iam.gserviceaccount.com" \
  --role="roles/artifactregistry.reader"
- Set that service account on the work pool template (as shown above:
service_account_name
). Docs: - Artifact Registry IAM roles - Cloud Run Jobs overview - Cloud Run service identity 3) Avoid optional features that add provisioning time - VPC connector: only set
vpc_connector_name
if you must reach private resources. Leaving it null removes the block and speeds up provisioning. Docs: Cloud Run VPC connectors - Memory/CPU: keep to the minimum your flow needs (e.g., memory “512Mi”, cpu “1000m”). Larger resources can slow scheduling/startup. - Extras: don’t set Cloud SQL integrations or other add-ons unless required. In the default Cloud Run v2 template, keep
cloudsql_instances
empty. Important note on startup time These changes reduce cold-start overhead, but Cloud Run Jobs can still take >10s depending on GCP scheduling and image pull. If <10s is a hard requirement, the fastest reliable path is a Docker worker on an always-on GCE VM with your image pre-pulled. I’m happy to share a ready-to-use systemd unit and minimal VM setup for that if you want. If you share your target region and repo/image names, I can draft a complete cr.json template for your work pool.
f
@Marvin I need much faster starts, how can I do?
m
thought for 131.1 seconds
To get consistently sub-10s starts, move off Cloud Run Jobs and run a pull-based worker on always-on compute that has your image pre-pulled. Given your container is already in Artifact Registry and you’re on Prefect 3, the fastest and simplest path on GCP is: Option A (fastest, still containerized): Docker worker on a small GCE VM - Expected startup: ~2–5s when the image is cached locally. - Why it’s fast: no serverless cold start; the worker is already running and launches a local container immediately. Setup steps 1) Create a Docker work pool
Copy code
prefect work-pool create "gce-docker" --type docker
2) Configure the pool’s base job template (so we don’t pull on every run) - Dump the default template:
Copy code
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
- Edit docker-pool.json: - Set "image" to your Artifact Registry image (with a pinned tag or digest) - Set "image_pull_policy" to "IfNotPresent" (or "Never" if you’ll always pre-pull) Example snippet:
Copy code
{
  "variables": {
    "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3",
    "image_pull_policy": "IfNotPresent",
    "env": {}
  }
}
- Apply:
Copy code
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
3) Provision a small GCE VM in the same region as your Artifact Registry - e2-small/e2-medium is usually enough. Install Docker and Prefect. - Authenticate Docker to AR and pre-pull your image:
Copy code
gcloud auth configure-docker REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3
4) Start the Prefect worker on the VM - Set Cloud API auth:
Copy code
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
export PREFECT_API_KEY="<YOUR_API_KEY>"
- Start worker:
Copy code
prefect worker start -p "gce-docker" -n "gce-docker-1"
- Optional: run it under systemd so it auto-restarts. 5) Deploy your flow using your prebuilt image (no builds) - In code:
Copy code
from prefect import flow

@flow
def my_flow():
    ...

if __name__ == "__main__":
    my_flow.deploy(
        name="prod",
        work_pool_name="gce-docker",
        image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3",
        build=False,
        push=False,
        job_variables={
            "image_pull_policy": "IfNotPresent"
        }
    )
Notes: - Using a pinned tag or digest avoids unexpected pulls. - If you set "image_pull_policy": "Never", ensure the image is always pre-pulled during VM boot/update. Option B (fastest absolute, no containers): Process worker on GCE VM - Expected startup: ~1s. - Tradeoff: you install your code and dependencies directly on the VM; no Docker isolation. - Steps are similar: create a process work pool, install your app on the VM, start a process worker, and deploy without specifying an image. Optional hardening and ops tips - Put the worker on a Managed Instance Group and use a startup script that: - Installs Docker + Prefect - Runs
gcloud auth configure-docker
- Pulls the image - Starts the worker (systemd) - Roll out image updates by pushing a new tag/digest and pre-pulling on the VMs before switching deployments. - Keep the VM and Artifact Registry in the same region to minimize pull time (even if you rarely pull). If you share: - Your region - The exact AR image path - Preference for Docker vs Process worker …I can give you a copy-paste systemd unit, a GCE startup script, and a minimal Terraform example to stand this up with image pre-pull and automatic worker start.
f
@Marvin what's the easier solution? What's the cheaper solution?
m
thought for 35.1 seconds
TL;DR - Easiest path to <10s: a single always-on GCE VM running a Docker worker, with your AR image pre-pulled. - Cheapest path to <10s: a single preemptible (spot) GCE VM running a Process worker (no Docker), if you can install deps directly. If you must use containers, use a Docker worker on a preemptible VM. Easiest (recommended given you already have a Docker image) - Why: You keep your existing container pipeline; minimal changes; reliably ~2–5s starts with cached image. - How: - Create a Docker work pool:
Copy code
prefect work-pool create "gce-docker" --type docker
- Configure the pool’s template to use your image and avoid pulls:
Copy code
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
Edit: - "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG" - "image_pull_policy": "IfNotPresent" (or "Never" if you always pre-pull) Apply:
Copy code
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
- On a small GCE VM in the same region as AR: -
gcloud auth configure-docker REGION-docker.pkg.dev
-
docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
- Start the worker:
Copy code
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
      export PREFECT_API_KEY="<YOUR_API_KEY>"
      prefect worker start -p "gce-docker" -n "gce-docker-1"
- Deploy with your prebuilt image and no build:
Copy code
flow.deploy(
      name="prod",
      work_pool_name="gce-docker",
      image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
      build=False,
      push=False,
      job_variables={"image_pull_policy": "IfNotPresent"}
    )
Cheapest (if you can drop containers) - Why: No Docker overhead; run on a tiny preemptible VM (60–70% cheaper). Startup ~1s. - How: - Package your code as a normal Python app on the VM (venv/uv/pip). - Create a Process work pool:
Copy code
prefect work-pool create "gce-process" --type process
- Start a worker:
Copy code
export PREFECT_API_URL=...
    export PREFECT_API_KEY=...
    prefect worker start -p "gce-process" -n "gce-process-1"
- Deploy without an image:
Copy code
flow.deploy(name="prod", work_pool_name="gce-process", build=False)
- Cost tips: use e2-micro/e2-small or t2a-standard-1 (ARM) if your stack supports ARM; consider preemptible (spot) to cut cost further. Keep VM and data in the same region. If containers are required and you want “cheapest” - Use the Docker worker on a preemptible e2-micro/e2-small (or ARM t2a) VM. - Pre-pull the image; set image_pull_policy to IfNotPresent/Never. Want me to drop in a ready-to-use systemd unit and a GCE startup script for either option? If you share your region and image path, I’ll tailor them.