oleander-whirlwind
10/20/2025, 8:20 AMMarvin
10/20/2025, 8:20 AMMarvin
10/20/2025, 8:22 AMprefect DB with user/password prefect
- Volume: Persists DB data across container restarts
- Healthcheck: Uses pg_isready to ensure the DB is ready before other services start
- redis
- Image: Redis 7
- Volume: Persists Redis data
- Healthcheck: Uses redis-cli ping to ensure Redis is responding
- prefect-server
- Image: prefecthq/prefect:3-latest
- Depends on: Waits until Postgres and Redis are healthy
- Environment:
- `PREFECT_API_DATABASE_CONNECTION_URL`: Tells Prefect Server how to connect to Postgres (async SQLAlchemy URL)
- `PREFECT_SERVER_API_HOST: 0.0.0.0`: Binds the API/UI to all interfaces in the container
- PREFECT_MESSAGING_* and `PREFECT_REDIS_*`: Configure Prefect’s messaging to use your Redis service
- Command: prefect server start --no-services --analytics-off
- Runs only the web server (UI + API). The actual services (scheduler, etc.) are started in a separate container (see next service).
- Ports: 4200:4200 exposes the UI and API at http://localhost:4200
- prefect-worker
- Image: prefecthq/prefect:3-latest
- Despite the name, this is the “server services” runner
- Depends on: Postgres/Redis healthy
- Environment: Same DB + Redis vars as the server (the services need these)
- Command: prefect server services start
- Starts all enabled Prefect services (scheduler, late runs, etc.) in one process
- Verified via prefect server services start --help
- prefect-worker-process
- Image: prefecthq/prefect:3-latest
- This is the actual worker that executes flows
- Depends on: prefect-server started (so it can reach the API)
- Environment:
- `PREFECT_API_URL`: Points the worker to your Prefect API (the internal service name prefect-server is correct inside the compose network)
- Command (needs a small fix; see below):
- You have: prefect worker start --pool worker-pool-example --type process
- Correct: prefect worker start --pool worker-pool-example
- The --type flag is not valid on prefect worker start in Prefect 3.x. The worker type is defined on the work pool itself when you create it.
- Verified with prefect worker start --help
Important fixes and recommendations
1) Remove angle brackets in environment values
- In your compose, you have:
- PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
- PREFECT_API_URL: <http://prefect-server:4200/api>
- Those angle brackets are placeholders — if left as-is, Prefect will read them literally and fail.
- Use:
- PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
- PREFECT_API_URL: <http://prefect-server:4200/api>
2) Fix the worker start command
- Create the work pool once (outside of compose) with the type:
- prefect work-pool create "worker-pool-example" --type process
- Then start your worker with:
- prefect worker start --pool worker-pool-example
- We validated the CLI:
- prefect worker start requires --pool and does not accept --type
- prefect work-pool create is where --type is used
3) Consider renaming services for clarityMarvin
10/20/2025, 8:22 AMprefect-worker → prefect-services (it runs the server services, not a worker)
- prefect-worker-process → prefect-worker (this is the actual worker)
4) Optional: add a healthcheck to prefect-server
- Right now, prefect-worker-process waits for service_started, not “healthy”.
- You can add a healthcheck to Prefect Server so the worker waits for the API to be live:
- Example:
healthcheck:
test: ["CMD-SHELL", "curl -sf <http://localhost:4200/api/health> || exit 1"]
interval: 5s
timeout: 5s
retries: 10
- Then change the worker’s depends_on to condition: service_healthy
Cleaned-up compose with the fixes applied
- This keeps your split “webserver” and “services” pattern, removes angle brackets, and fixes the worker command.
services:
postgres:
image: postgres:14
environment:
POSTGRES_USER: prefect
POSTGRES_PASSWORD: prefect
POSTGRES_DB: prefect
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U prefect"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7
volumes:
- redis_data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping"]
interval: 5s
timeout: 5s
retries: 5
prefect-server:
image: prefecthq/prefect:3-latest
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
PREFECT_SERVER_API_HOST: 0.0.0.0
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: 6379
PREFECT_REDIS_MESSAGING_DB: 0
command: prefect server start --no-services --analytics-off
ports:
- "4200:4200"
# Optional: add a healthcheck so workers wait for a healthy API
# healthcheck:
# test: ["CMD-SHELL", "curl -sf <http://localhost:4200/api/health> || exit 1"]
# interval: 5s
# timeout: 5s
# retries: 10
prefect-services:
image: prefecthq/prefect:3-latest
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: 6379
PREFECT_REDIS_MESSAGING_DB: 0
command: prefect server services start
prefect-worker:
image: prefecthq/prefect:3-latest
depends_on:
prefect-server:
condition: service_started # change to service_healthy if you add the healthcheck
environment:
PREFECT_API_URL: <http://prefect-server:4200/api>
command: prefect worker start --pool worker-pool-example
volumes:
postgres_data:
redis_data:
How to bring this up and run flows
1) Start the stack:
- docker compose up -d
- UI will be at http://localhost:4200
2) Create the work pool (one time):
- prefect work-pool create "worker-pool-example" --type process
3) Start your worker (compose already does this). It will poll the pool and execute runs.
Notes
- The PREFECT_MESSAGING_* settings are configuring Prefect’s messaging provider to use Redis. The host/port/db point to your Redis service.
- For production, change your Postgres credentials, consider secrets management, and ensure you persist volumes and secure the UI/API behind your network policies or a reverse proxy.
- If you prefer a simpler setup, you can run everything in a single container with prefect server start (without --no-services) and remove the prefect-services container.Marvin
10/20/2025, 8:22 AMoleander-whirlwind
10/20/2025, 8:33 AMMarvin
10/20/2025, 8:33 AMMarvin
10/20/2025, 8:36 AMprefect server start
- Components used by default:
- Database: SQLite (a local file under your Prefect home directory); no Postgres needed
- Messaging/Cache: In-memory; no Redis needed
- Services: Background services (scheduler, late-run detection, etc.) run in the same process by default
- UI/API: http://127.0.0.1:4200
- Notes:
- Add --no-services if you only want the web UI/API and plan to run services separately (less common locally)
- You can still override to use Postgres/Redis by setting env vars like PREFECT_API_DATABASE_CONNECTION_URL or PREFECT_MESSAGING_*
Run a worker locally against Prefect Cloud (no local server)
- You don’t need any local Postgres/Redis or a local server
- Set your API to Cloud and start a worker:
prefect config set PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<acct>/workspaces/<ws>>
prefect work-pool create my-pool --type process # one-time
prefect worker start --pool my-pool
- The worker polls Prefect Cloud and executes flows locally
Self-hosted with external services (still without Compose)
- If you do want Postgres/Redis without Compose, you can point Prefect at them:
export PREFECT_API_DATABASE_CONNECTION_URL=<postgresql+asyncpg://user:pass@host:5432/db>
export PREFECT_MESSAGING_BROKER=prefect_redis.messaging
export PREFECT_MESSAGING_CACHE=prefect_redis.messaging
export PREFECT_REDIS_MESSAGING_HOST=redis-host
export PREFECT_REDIS_MESSAGING_PORT=6379
prefect server start
- This mirrors what your Compose file did but with your own managed services
What runs by default (summary)
- Database: SQLite (local file)
- Messaging: in-memory
- Cache: in-memory
- Services: enabled, run in-process with the server unless you use --no-services
Relevant docs for deeper detail
- Server CLI: prefect server CLI
- Settings (DB and messaging): Prefect settings reference
- Workers and pools: Workers and Work Pools
- Self-hosting overview: Self-hosting Prefect
If by “fn” you meant Prefect Functions (Cloud), those do not use your local Postgres/Redis either — they run on Prefect’s managed infrastructure. Let me know which “fn” you meant and I’ll tailor the specifics.oleander-whirlwind
10/20/2025, 8:38 AMMarvin
10/20/2025, 8:38 AMMarvin
10/20/2025, 8:42 AMoleander-whirlwind
10/20/2025, 8:43 AM