Rasmus Simmelkjær Berntsen
11/16/2025, 2:57 PMMarvin
11/16/2025, 2:57 PMMarvin
11/16/2025, 3:03 PMversion: "3.9"
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: prefect
POSTGRES_USER: prefect
POSTGRES_PASSWORD: prefect
ports:
- "5432:5432"
# API replica 1
prefect-api-1:
image: prefecthq/prefect:3-latest
command: >
prefect server start
--no-services
--host 0.0.0.0
--port 4200
environment:
PREFECT_SERVER_DATABASE__CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
# Tune SQLAlchemy pool to your load profile
PREFECT_SERVER_DATABASE__SQLALCHEMY__POOL_SIZE: "20"
PREFECT_SERVER_DATABASE__SQLALCHEMY__MAX_OVERFLOW: "20"
PREFECT_SERVER_DATABASE__SQLALCHEMY__POOL_RECYCLE: "300"
depends_on:
- postgres
# API replica 2
prefect-api-2:
image: prefecthq/prefect:3-latest
command: >
prefect server start
--no-services
--host 0.0.0.0
--port 4200
environment:
PREFECT_SERVER_DATABASE__CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
PREFECT_SERVER_DATABASE__SQLALCHEMY__POOL_SIZE: "20"
PREFECT_SERVER_DATABASE__SQLALCHEMY__MAX_OVERFLOW: "20"
PREFECT_SERVER_DATABASE__SQLALCHEMY__POOL_RECYCLE: "300"
depends_on:
- postgres
# Singleton background services (scheduler, etc.)
prefect-services:
image: prefecthq/prefect:3-latest
command: prefect server services start
environment:
PREFECT_SERVER_DATABASE__CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
depends_on:
- postgres
- Put a reverse proxy / load balancer in front of prefect-api-1 and prefect-api-2 (e.g., NGINX, ALB, etc).
- Point all clients/workers at the LB:
- PREFECT_API_URL=<https://your-lb.example.com/api>
Kubernetes outline
- Deployment: prefect-api with replicas: 2
- Container command: prefect server start --no-services --host 0.0.0.0 --port 4200
- Env: DB connection URL and SQLAlchemy pool tuning
- Service + Ingress/ALB in front
- Deployment: prefect-services replicas: 1
- Command: prefect server services start
- Env: DB connection URL
- All workers and CLI clients use PREFECT_API_URL pointing at the prefect-api Service/Ingress.
When to add Redis and howMarvin
11/16/2025, 3:03 PMRasmus Simmelkjær Berntsen
11/17/2025, 2:58 PMMarvin
11/17/2025, 2:58 PMMarvin
11/17/2025, 3:03 PMprefect server services ls
You should see entries for triggers (reactive/proactive), event_persister, event_logger, scheduler, etc. If they aren’t running:
prefect server services start
Tail logs there to catch errors (e.g., broker import errors).
2) Verify both API and services use the same messaging backend (Redis)
- In Prefect 3.x the defaults are in‑memory:
- server.events.messaging_broker = prefect.server.utilities.messaging.memory
- server.events.messaging_cache = prefect.server.utilities.messaging.memory
- In your deployment, set BOTH to the Redis implementation from the prefect-redis integration and ensure the same settings are present in:
- all API replicas
- the background services process
- You can confirm the server’s effective settings by hitting the admin settings endpoint on any API instance:
GET /api/admin/settings
Look for server.events.messaging_broker and server.events.messaging_cache. They must point to the Redis messaging modules (not memory) and match between API and services.
- Also ensure the Redis connection URL you’re using is reachable from both API and services.
3) Ensure prefect-redis is installed everywhere
- The API image(s) and the services image must both have the integration:
pip install prefect-redis
If it’s missing in the services container, you’ll see import errors or it will silently fall back to memory.
4) Check automation action feasibility
- If your automation uses RunDeployment:
- Confirm the deployment slug exists and matches exactly.
- Confirm the target work pool exists and at least one worker is online; otherwise a run will not be picked up.
- If the action is something else (e.g., SendNotification), check for errors in the services logs.
5) Look for errors in services logs
- The triggers/event_persister services will log if they cannot connect to Redis, can’t import the broker, or fail an action.
If you can share:
- The output of prefect server services ls
- The relevant pieces of your env/config showing the values you set for:
- PREFECT_SERVER_EVENTS__MESSAGING_BROKER
- PREFECT_SERVER_EVENTS__MESSAGING_CACHE
- your Redis URL/config
- Whether the automation action is RunDeployment (and the target work pool/worker status)
…I can pinpoint the misconfig quickly.
References
- Server concepts: Prefect Server concepts
- Settings reference (events messaging): Prefect settings reference
- Redis integration: prefect-redis integrationRasmus Simmelkjær Berntsen
11/18/2025, 5:46 AMMarvin
11/18/2025, 5:46 AMcheck_cli_command
📊 Tools used:
• check_cli_command (1x)Marvin
11/18/2025, 5:50 AMprefect server services ls in Prefect 3.x. Here’s how to interpret and control these services, plus links to docs and CLI help.
What each service does (quick guide)
- Scheduler: Schedules flow runs from deployments.
- RecentDeploymentsScheduler: Accelerates scheduling for deployments updated very recently.
- Foreman: Monitors workers and their work pools.
- CancellationCleanup: Cancels tasks/subflows of cancelled flow runs.
- MarkLateRuns: Marks runs late if they’re past their scheduled start time.
- FailExpiredPauses: Fails runs that were paused but never resumed before expiration.
- Repossessor: Reconciles expired leases.
- TaskRunRecorder: Builds task runs and states from client-emitted events.
- Triggers (Proactive/Reactive/Actions): Evaluates automations and runs their actions.
- EventLogger: Debug service that logs incoming events to the server console (disabled by default to avoid noise).
- EventPersister: Persists incoming events to the DB.
- LogDistributor: Streams logs to websocket subscribers (disabled by default).
- Distributor: Marker service for things that should run in ephemeral mode.
How to enable/disable
- Toggle each with an environment variable using the pattern shown in your table: PREFECT_SERVER_SERVICES_<SERVICE>_ENABLED=true|false
- For log streaming specifically, use PREFECT_SERVER_LOGS_STREAM_OUT_ENABLED=true (controls the LogDistributor).
- Changes take effect when the services process (or container) restarts.
Examples
# Enable EventLogger (prints events to server logs; noisy but useful for debugging)
PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED=true
# Enable log streaming over websockets (for live logs)
PREFECT_SERVER_LOGS_STREAM_OUT_ENABLED=true
# Disable LateRuns service
PREFECT_SERVER_SERVICES_LATE_RUNS_ENABLED=false
Docker Compose snippet (if you’re running the “prefect-services” container)
services:
prefect-services:
environment:
- PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED=true
- PREFECT_SERVER_LOGS_STREAM_OUT_ENABLED=true
CLI you can use
- List services/status:
prefect server services ls
- Start all enabled services in one process:
prefect server services start
- Stop background services started by the command above:
prefect server services stop
Docs and references
- Server services CLI: CLI reference: prefect server services
- Settings reference (all env vars + defaults): Settings reference
- Scheduler: Scheduler service
- Foreman: Foreman service
- Late runs: LateRuns service
- Cancellation cleanup: CancellationCleanup service
- Pause expirations: FailExpiredPauses service
- Repossessor: Repossessor service
- Event logger: EventLogger service
- Event persister: EventPersister service
- Triggers: Triggers services
- Log distributor: LogDistributor
- Self-hosted guide (Compose): Self-hosted with Docker ComposeMarvin
11/18/2025, 5:50 AMRasmus Simmelkjær Berntsen
11/18/2025, 5:51 AMMarvin
11/18/2025, 5:51 AMMarvin
11/18/2025, 5:52 AMprefect server services ls
- You should see:
- ProactiveTriggers / ReactiveTriggers / Actions: Enabled ✓
- EventPersister: Enabled ✓
- Scheduler: Enabled ✓
- Foreman: Enabled ✓ (helps monitor workers/pools)
2) If you don’t have a “services” process
- Start one as a dedicated K8s Deployment (example below) that runs all enabled services:
prefect server services start
- Ensure env vars include:
PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
PREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED=true
3) If your automation action is “Run deployment”
- Check the UI to see if a flow run is being created when the automation fires.
- If a flow run exists but stays Scheduled, that means no worker picked it up:
- Verify the target work pool/queue is correct and not paused.
- Ensure a worker is connected to the right API URL and polling that pool.
- Check worker logs or prefect worker inspect for Last polled times.
- Foreman being healthy helps detect “no worker polling” cases.
4) Look for errors in logs
- Services pod logs should show the Triggers/Actions services starting and any action execution messages.
- API pod logs may show action creation attempts or errors.
- If you rely on events for trigger conditions, EventPersister must be running.
Minimal K8s Deployment for services (add alongside your API)
apiVersion: apps/v1
kind: Deployment
metadata:
name: prefect-services
spec:
replicas: 1
selector:
matchLabels:
app: prefect-services
template:
metadata:
labels:
app: prefect-services
spec:
containers:
- name: services
image: prefecthq/prefect:3-latest
command: ["sh","-lc","prefect server services start"]
env:
- name: PREFECT_API_URL
value: "http://<your-api-service>:4200/api"
# Ensure triggers and event persister are on
- name: PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED
value: "true"
- name: PREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED
value: "true"
# You can also enable Scheduler here (or keep it in your existing scheduler pod)
- name: PREFECT_SERVER_SERVICES_SCHEDULER_ENABLED
value: "true"
If you already have a services pod, please share:
- Prefect version
- The automation’s action type(s)
- Output of prefect server services ls from that pod
- Whether a flow run is created when the automation fires (and its state)
- Any relevant logs mentioning “triggers” or “actions”
Helpful references
- CLI for services: prefect server services CLI
- Settings reference (env vars): Settings reference
- Triggers/Actions service: Triggers services
- Event persister: EventPersister
- Scheduler: Scheduler
- Foreman: ForemanMarvin
11/18/2025, 5:52 AMRasmus Simmelkjær Berntsen
11/18/2025, 6:34 AMMarvin
11/18/2025, 6:34 AMMarvin
11/18/2025, 6:34 AMRasmus Simmelkjær Berntsen
11/18/2025, 6:35 AMMarvin
11/18/2025, 6:35 AMcheck_cli_command
📊 Tools used:
• check_cli_command (4x)
• explore_module_offerings (1x)
• read_github_issues (1x)Marvin
11/18/2025, 6:42 AMprefect server services ls
You should see ProactiveTriggers, ReactiveTriggers, and Actions as Enabled ✓.
2) Inspect the automation to confirm it has actions_on_trigger
prefect automation ls
prefect automation inspect <automation-id>
Look for actions_on_trigger vs actions_on_resolve.
3) Look explicitly for action execution/failure logs and events
Remove the grep or use a broader one:
# In the background/services pod
kubectl logs -n prefect <your-services-pod> --since=30m | \
grep -E "events\.actions|automation\.action|ActionFailed|ActionSucceeded|SendNotification|RunDeployment"
You should see messages from prefect.server.events.actions and events like:
- prefect.automation.action.attempted
- prefect.automation.action.succeeded
- prefect.automation.action.failed
4) Validate config in the services pod
prefect config view --show-defaults --show-sources | \
grep -E "PREFECT_SERVER_SERVICES_TRIGGERS|PREFECT_API_URL|PREFECT_API_DATABASE"
- Ensure PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
- Ensure PREFECT_API_URL points to your API service
- Ensure the DB connection matches your API pods’
5) If the action is SendNotification (your name suggests a Teams notification)
- Confirm the MicrosoftTeamsWebhook block exists and the automation references it correctly (slug/name).
- From the services pod, test basic egress to your Teams webhook host (to rule out egress or proxy issues).
- If the block can’t be loaded or the POST fails, you’ll see an action.failed log.
6) If the action is RunDeployment
- Check whether a flow run was created when the automation fired (UI or CLI):
prefect flow-run ls --limit 20
- If created but stuck Scheduled:
- Verify the target work pool/queue and that it’s not paused.
- Ensure a worker is polling that pool (right API URL, last polled time).
- Check prefect work-pool inspect <name> and worker logs.
Optionally enable extra diagnostics
- Temporarily enable the event logger to see events in the services pod:
PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED=true
If you can share:
- Prefect version (prefect version)
- Output of prefect server services ls from the background pod
- prefect automation inspect <id> for one failing automation
- Any lines that match the “action” grep above
…I can pinpoint whether it’s a missing Actions runner, a misconfigured notification block, network egress, or a worker pickup issue.
Docs for reference
- CLI: prefect server services
- Automations/actions internals: Actions API
- Triggers service: Triggers/Actions service
- Settings reference: SettingsRasmus Simmelkjær Berntsen
11/18/2025, 6:50 AMMarvin
11/18/2025, 6:50 AMMarvin
11/18/2025, 6:51 AMprefect server services ls
You should see ProactiveTriggers, ReactiveTriggers, and Actions as Enabled ✓. If Actions is not enabled, set:
PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
and restart the pod. Also verify the pod is started with:
prefect server services start
2) Check settings in that pod
prefect config view --show-defaults --show-sources | grep -E "PREFECT_SERVER_SERVICES_TRIGGERS|PREFECT_API_URL|PREFECT_LOGGING_SERVER_LEVEL"
- Ensure PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
- Ensure PREFECT_API_URL points at your API service
- Consider raising verbosity:
- PREFECT_LOGGING_SERVER_LEVEL=DEBUG
3) Search for action execution logs (broader than “automation”)
# Last 30 minutes of logs; broaden patterns
kubectl logs -n prefect <your-services-pod> --since=30m | \
grep -E "prefect\.server\.events\.actions|automation\.action|ActionFailed|ActionSucceeded|SendNotification|RunDeployment"
If actions are running, you should see events like:
- prefect.automation.action.attempted
- prefect.automation.action.succeeded
- prefect.automation.action.failed
4) Inspect the automation to confirm it actually has actions_on_trigger
prefect automation ls
prefect automation inspect f3260518-7304-4960-95ec-d79af071e003
prefect automation inspect a8aebf97-183f-4600-a46e-1f7b57880f14
Look for an action in actions_on_trigger (e.g., SendNotification with a MicrosoftTeamsWebhook block). If there are only actions_on_resolve, you’ll see triggers but no immediate action.
5) If it’s a Teams notification
- Confirm the block exists with the expected name/slug.
- Check egress from the services pod to your Teams webhook host (network/policy/proxy).
- If it fails to send, you’ll get an action.failed log (which your current grep would miss).
6) If it’s a RunDeployment action
- Check for new flow runs when the automation fires:
prefect flow-run ls --limit 20
If a flow run is created but stays Scheduled, it’s a worker pickup issue:
- Verify the work pool/queue is correct and not paused.
- Ensure a worker is polling that pool, connected to the same API URL.
If you share:
- Output of prefect server services ls from the background pod
- The prefect automation inspect output for one of these automations
- The broader grep results above (or last 200 lines without grep)
…I can pinpoint if the Actions runner isn’t active, if the automation lacks trigger actions, or if there’s a notification/block/egress or worker pickup issue.
Refs
- CLI: prefect server services
- Actions internals: Actions API
- Triggers service: Triggers/Actions service