Jordan Jones
11/18/2025, 5:06 PMMarvin
11/18/2025, 5:06 PMMarvin
11/18/2025, 5:10 PMfollows but the “preceding” event is missing or delayed, try omitting follows to see if latency drops.
- Watch for retries/rate limits
- Look for 429 or retry logs where you emit events. Bursts can be smoothed (e.g., add small client-side backoff).
- For self-hosted (OSS)
- Ensure your server/postgres are well resourced. Large, unpartitioned event tables slow queries; consider retention tuning and partitioning.
- Check server logs for the events persister/triggers services for backlogs or slow queries.
If you can share a bit more, I can be more specific:
- Are you on Prefect Cloud or self‑hosted?
- Roughly how long is the lag (seconds/minutes)? Is it consistent or sporadic?
- Is the trigger reactive or proactive?
- Approximate event volume when you see the lag?
- An example event name and when you sent it (timestamp), plus what the trigger filter looks like.
Relevant docs
- Event triggers overview: Event triggers in Prefect 3.x
- Emitting events (SDK): Events utilities API
- Events REST endpoint: Create events API
- Triggers services (reactive/proactive): Triggers services
- Database considerations: Database maintenance and performanceJordan Jones
11/18/2025, 5:22 PMMarvin
11/18/2025, 5:22 PMMarvin
11/18/2025, 5:31 PMcurl -s -X POST "$PREFECT_API_URL/api/events/count-by/type" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filter":{"occurred":{"since":"5m"}}}'
- Stream: connect a WebSocket to your server’s events-out to watch live
- ws URL is typically at /api/events/out (filterable)
- DB (safest): on your Prefect Postgres
-- Do you see events arriving right away?
SELECT COUNT(*)
FROM event
WHERE occurred > NOW() - INTERVAL '5 minutes';
2) Check that an automation fires on those events
- In the UI, open Automations and check “Last triggered” and recent activity.
- DB (optional): do you see new flow runs right after relevant events?
SELECT id, created, state_type, deployment_id
FROM flow_run
WHERE created > NOW() - INTERVAL '15 minutes'
ORDER BY created DESC
LIMIT 50;
3) Check run scheduling latency
- Are runs stuck in SCHEDULED for a long time before going PENDING?
SELECT id, created, expected_start_time, start_time, state_type
FROM flow_run
WHERE created > NOW() - INTERVAL '30 minutes'
ORDER BY created DESC
LIMIT 100;
- If they linger in SCHEDULED, the Scheduler loop is your likely bottleneck.
4) Check worker pickup
- Worker logs: frequent polls and immediate submission after runs become PENDING
- Ensure enough workers are online, and that work pool concurrency isn’t limiting.
Server-side tuning for higher event volume
If you’re doing a few thousand events/minute, these settings typically cut end-to-end latency substantially. Set them on your API server(s) and restart.
- Event persister (batching/flush)
PREFECT_SERVER_SERVICES_EVENT_PERSISTER_BATCH_SIZE=500
PREFECT_SERVER_SERVICES_EVENT_PERSISTER_FLUSH_INTERVAL=2
- Scheduler (loop frequency and batch inserts)
PREFECT_SERVER_SERVICES_SCHEDULER_LOOP_SECONDS=30
PREFECT_SERVER_SERVICES_SCHEDULER_INSERT_BATCH_SIZE=2000
- Automations (time-based trigger evaluation granularity)
PREFECT_SERVER_EVENTS_PROACTIVE_GRANULARITY=2
- Messaging broker for events (recommended at your scale)
- Default is in-memory; switch to Redis to decouple ingestion under load. Install the Redis integration and point the broker at it:
# Install integration in your server image/env:
# pip install "prefect-redis" (or add to your image)
# Use Redis-backed messaging
PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect_redis.messaging
PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect_redis.messaging
# Redis connection settings
PREFECT_REDIS_MESSAGING_HOST=redis
PREFECT_REDIS_MESSAGING_PORT=6379
PREFECT_REDIS_MESSAGING_DB=0
# PREFECT_REDIS_MESSAGING_PASSWORD=...
Additional checks
- Postgres health: watch CPU, IOPS, and connection limits. At high write rates from events + scheduler, under-provisioned Postgres will cause backpressure.
- Indexes: ensure standard indexes exist; if your DB was migrated from an older version, missing indexes can slow queries. If you see slow queries in logs, we can dig into specific indexes.
- Time sync: ensure all components (API, DB, workers) have synchronized clocks (NTP). Clock skew can manifest as “scheduled in the future” delays.
- Worker capacity: add workers or increase concurrency for the affected work pool if runs transition to PENDING quickly but sit waiting for pickup.Marvin
11/18/2025, 5:31 PMJordan Jones
11/18/2025, 5:34 PMMarvin
11/18/2025, 5:35 PMMarvin
11/18/2025, 5:36 PMcurl -i -X POST "$PREFECT_API_URL/api/events" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"occurred": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
"event": "test.event.ingestion",
"resource": {"prefect.resource.id": "demo:ingestion"},
"payload": {"foo": "bar"}
}
]
}'
- Expect a 204. If not 204, share the status/body.
2) Watch events live via WebSocket (server-side)
- Connect a WS client to: ws://<your-api>/api/events/out
- If your test event doesn’t show up here, the API isn’t accepting/processing it.
3) Re-check DB directly after the test
SELECT COUNT(*)
FROM event
WHERE occurred > NOW() - INTERVAL '5 minutes';
If still 0, check these right away
- Are you running multiple API replicas or a multi-process server?
- If yes, switch to Redis for event messaging (in-memory broker is single-process only).
Enable verbose event logging temporarily
- This logs all received events at the API:
PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED=true
Restart the API and watch logs as you POST the test event.
Recommended fix for multi-replica/multi-process
- Install Redis messaging integration in your API image/env:
pip install "prefect-redis"
- Configure the broker to use Redis and restart API:
PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect_redis.messaging
PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect_redis.messaging
PREFECT_REDIS_MESSAGING_HOST=redis # or your host
PREFECT_REDIS_MESSAGING_PORT=6379
PREFECT_REDIS_MESSAGING_DB=0
# PREFECT_REDIS_MESSAGING_PASSWORD=...
Other things to double-check
- Client config:
- The process emitting events must have the same PREFECT_API_URL and an API key for the correct workspace.
- If you’re using a Prefect client emitter, check logs for HTTP failures; the emitter may log “emitted” on enqueue, not on successful persistence.
- Event persister status:
- Ensure the API includes services; look for “event_persister” logs or errors on startup.
- Table exists:
SELECT table_name
FROM information_schema.tables
WHERE table_schema='public' AND table_name LIKE 'event%';
If you can share:
- How you’re running Prefect (Docker Compose vs K8s/Helm), and number of API replicas/processes
- Values of PREFECT_API_URL, whether you use PREFECT_API_KEY
- Whether you can reproduce with the curl test and the HTTP status code you get
- A short snippet of your API logs around “event_persister” during the test
Once we confirm ingestion works (DB count increases or WS shows events), we can tune batching/flush intervals and scheduler settings to reduce end-to-end latency. For reference:
- Self-hosting overview: Self-hosting Prefect
- Automations and events concepts: Automations and Events