鹿野孟城
03/03/2026, 3:07 AMMarvin
03/03/2026, 3:07 AMMarvin
03/03/2026, 3:10 AMkubectl logs deploy/<your-prefect-api-deployment> | egrep -i "EventPersister|Triggers|Actions|Distributor|event"
If you don’t see these or see errors, share that snippet.
3) Check the database has event tables and whether any records exist
- From your DB, verify tables and row counts:
-- PostgreSQL example
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' AND table_name IN ('events', 'event_resources');
SELECT COUNT(*) FROM events;
If the tables are missing or count is 0 even after a test event (next step), the persister isn’t writing.
4) Emit a test event directly to the API
- Port-forward or hit your service internally, then POST a simple event:
# adjust host/port to your API Service or port-forward target
curl -X POST http://<api-host>:<port>/api/events \
-H "Content-Type: application/json" \
-d '[{
"occurred": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
"event": "diagnostic.test",
"resource": {"prefect.resource.id": "diagnostic/test"}
}]'
Expected: HTTP 204. Then re-check:
SELECT COUNT(*) FROM events;
5) Query events via the API
- If the feed UI is empty, see if the API can return them:
curl -X POST http://<api-host>:<port>/api/events/filter \
-H "Content-Type: application/json" \
-d '{"filter": {"events": ["*"]}, "limit": 5}'
If this returns your test event, the server is capturing events; the issue is likely WebSocket/ingress.
6) Check the UI WebSocket connection
- In your browser dev tools Network tab, locate a WebSocket to /api/events/out.
- If it fails/doesn’t connect:
- Ensure PREFECT_SERVER_EVENTS_STREAM_OUT_ENABLED=true on the API pod(s).
- Check your ingress/proxy upgrades WebSockets and doesn’t buffer/close them. Example NGINX location block for WebSockets:
location /api/events/out {
proxy_pass http://<prefect-api-service>;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
7) Confirm key environment variables in the API pod(s)
- These should be set (defaults are generally okay, but verifying helps):
PREFECT_SERVER_EVENTS_STREAM_OUT_ENABLED=true
PREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED=true
PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
PREFECT_SERVER_SERVICES_ACTIONS_ENABLED=true
# Optional tuning:
# PREFECT_SERVER_EVENTS_RETENTION_PERIOD=604800
- If you’re running multiple API replicas or want durability across restarts, use a shared broker (Redis) instead of the default in-memory queue:
# requires the prefect-redis extra installed in your image
PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect_redis.messaging
PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect_redis.messaging
# (Configure your Redis connection per your environment)
Note: With multiple API replicas and in-memory messaging, events can be dropped or only visible on a single pod; a shared broker avoids that.
8) Turn on debug to see event activity
- Temporarily enable:
```Marvin
03/03/2026, 3:10 AMThen check logs for lines like “Received event” and “Persisting X events”.
If you’re behind an ingress/proxy
- Ensure your `PREFECT_API_URL` in the UI resolves to your public/API ingress URL.
- Verify WebSocket upgrade headers/timeouts as shown above.
- If TLS-terminating, make sure the proxy passes the correct scheme/host headers.
If nothing shows after these steps
- Please share:
- Prefect version
- How you deployed (Helm chart or custom manifests)
- Number of API replicas
- The API pod env vars related to `PREFECT_*EVENT*` and service enables
- Ingress controller and any special config (snippets for `/api/events` and `/api/events/out`)
- A few lines of API pod logs around startup mentioning EventPersister/Distributor
- DB type/version and results of the SQL checks above
Optional: minimal Deployment env example
env:
- name: PREFECT_LOGGING_LEVEL
value: INFO
- name: PREFECT_SERVER_EVENTS_STREAM_OUT_ENABLED
value: "true"
- name: PREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED
value: "true"
- name: PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED
value: "true"
- name: PREFECT_SERVER_SERVICES_ACTIONS_ENABLED
value: "true"
# For single replica, in-memory is fine; for >1 replica, switch to Redis:
# - name: PREFECT_SERVER_EVENTS_MESSAGING_BROKER
# value: prefect_redis.messaging
# - name: PREFECT_SERVER_EVENTS_MESSAGING_CACHE
# value: prefect_redis.messaging
# - name: REDIS_URL
# value: redis://redis:6379/0 # example; match your setup
```
Share your pod spec and logs when you can, and I’ll pinpoint the next steps quickly.鹿野孟城
03/03/2026, 3:20 AM03:18:11.265 | INFO | prefect.server.events.services.triggers - ReactiveTriggers starting with unique consumer name: reactive-triggers-prefect-server-background-services-56c458c47d-h4xwf-8-553a9173
03:18:11.275 | INFO | prefect.server.events.actions - Starting action message handler
03:18:11.276 | INFO | prefect.server.services.task_run_recorder - Starting periodically process followers task every 5.0 seconds
03:18:11.277 | INFO | prefect.server.events.triggers - Starting automation change listener
Event: 019cb152 2026-03-03T01:32:08.233005+00:00 (-6,363.09)
[prefect.deployment.ready]
prefect.deployment.02222e6e-01a4-4c2f-9b0f-0733d1a131ee
03:18:11.551 | INFO | prefect.server.utilities.postgres_listener - Successfully established raw asyncpg connection for LISTEN/NOTIFY to <http://prefect-db.cqvqerbpboys.ap-northeast-1.rds.amazonaws.com:5432/prefectdb|prefect-db.cqvqerbpboys.ap-northeast-1.rds.amazonaws.com:5432/prefectdb>
03:18:11.551 | INFO | prefect.server.events.triggers - Listening for automation changes on prefect_automation_changes
03:18:11.665 | INFO | prefect.server.utilities.postgres_listener - Listening on Postgres channel: prefect_automation_changes
03:18:11.773 | INFO | prefect.server.services.recentdeploymentsscheduler - Scheduled 0 runs.
03:18:11.819 | INFO | prefect.server.services.marklateruns - Finished monitoring for late runs.
03:18:11.820 | INFO | prefect.server.services.failexpiredpauses - Finished monitoring for late runs.
03:18:11.822 | INFO | prefect.server.services.scheduler - Scheduled 0 runs.
03:18:11.843 | INFO | prefect.server.services.cancellationcleanup - Finished cleaning up cancelled flow runs.
03:18:16.266 | INFO | prefect.server.services.failexpiredpauses - Finished monitoring for late runs.
03:18:16.270 | INFO | prefect.server.services.recentdeploymentsscheduler - Scheduled 0 runs.
03:18:16.273 | INFO | prefect.server.services.marklateruns - Finished monitoring for late runs.
03:18:21.267 | INFO | prefect.server.services.marklateruns - Finished monitoring for late runs.
03:18:21.267 | INFO | prefect.server.services.failexpiredpauses - Finished monitoring for late runs.
03:18:21.270 | INFO | prefect.server.services.recentdeploymentsscheduler - Scheduled 0 runs.
03:18:26.264 | INFO | prefect.server.services.marklateruns - Finished monitoring for late runs.
03:18:26.267 | INFO | prefect.server.services.failexpiredpauses - Finished monitoring for late runs.
03:18:26.273 | INFO | prefect.server.services.recentdeploymentsscheduler - Scheduled 0 runs.Marvin
03/03/2026, 3:20 AMMarvin
03/03/2026, 3:21 AMPREFECT_SERVER_SERVICES_EVENT_PERSISTER_ENABLED=true
PREFECT_SERVER_EVENTS_STREAM_OUT_ENABLED=true
PREFECT_SERVER_SERVICES_TRIGGERS_ENABLED=true
PREFECT_SERVER_SERVICES_ACTIONS_ENABLED=true
# Optional for debugging:
# PREFECT_LOGGING_LEVEL=DEBUG
# PREFECT_SERVER_SERVICES_EVENT_LOGGER_ENABLED=true
- After restarting, you should see a line similar to:
prefect.server.events.services.event_persister - Starting EventPersister
2) If you run multiple replicas of the API/background-services
- Use a shared broker (Redis) instead of the default in-memory queue to avoid lost/partitioned events:
# Ensure your image includes the prefect-redis extra and configure Redis URL
PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect_redis.messaging
PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect_redis.messaging
# plus your Redis connection settings
3) Verify the DB has event tables and whether events are being recorded
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' AND table_name IN ('events', 'event_resources');
SELECT COUNT(*) FROM events;
- If tables exist but count stays 0 after the test below, EventPersister isn’t writing.
4) Emit a test event and confirm it lands
curl -X POST http://<api-host>:<port>/api/events \
-H "Content-Type: application/json" \
-d '[{
"occurred": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
"event": "diagnostic.test",
"resource": {"prefect.resource.id": "diagnostic/test"}
}]'
- Expect 204 response; then:
SELECT COUNT(*) FROM events;
- Also try fetching via API:
curl -X POST http://<api-host>:<port>/api/events/filter \
-H "Content-Type: application/json" \
-d '{"filter": {"events": ["*"]}, "limit": 5}'
5) Check the UI WebSocket to the event feed
- In browser dev tools, confirm a WebSocket to /api/events/out connects. If it fails:
- Ensure PREFECT_SERVER_EVENTS_STREAM_OUT_ENABLED=true
- Verify your ingress/proxy upgrades WebSockets. Example NGINX location:
location /api/events/out {
proxy_pass http://<prefect-api-service>;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
6) Get targeted logs
kubectl logs deploy/<your-prefect-api-or-background-deploy> | egrep -i "event_persister|event persister|events.services|Distributor|websocket|event logger|prefect.server.events"
- Share any errors or absence of EventPersister startup.
If you can, please share:
- The Deployment(s) Pod spec env for your API/background-services (redact secrets)
- Number of replicas for those pods
- Ingress controller and any relevant location blocks for /api/events and /api/events/out
- Result of the SQL checks and the test-event POST
- A few lines of logs around startup that would include EventPersister/DistributorMarvin
03/03/2026, 3:21 AM鹿野孟城
03/03/2026, 3:26 AMhome: /home/prefect/.prefect
profiles_path: /home/prefect/.prefect/profiles.toml
debug_mode: false
api: {
"url": null,
"auth_string": null,
"key": null,
"tls_insecure_skip_verify": false,
"ssl_cert_file": null,
"enable_http2": false,
"request_timeout": 60
}
cli: {
"colors": true,
"prompt": null,
"wrap_lines": true
}
client: {
"max_retries": 5,
"retry_jitter_factor": 0.2,
"retry_extra_codes": [],
"csrf_support_enabled": true,
"custom_headers": {},
"metrics": {
"enabled": true,
"port": 4201
}
}
cloud: {
"api_url": "<https://api.prefect.cloud/api>",
"enable_orchestration_telemetry": true,
"max_log_size": 25000,
"ui_url": "<https://app.prefect.cloud>"
}
deployments: {
"default_work_pool_name": null,
"default_docker_build_namespace": null
}
experiments: {
"warn": true,
"plugins": {
"enabled": false,
"allow": [],
"deny": [],
"setup_timeout_seconds": 20,
"strict": false,
"safe_mode": false
}
}
flows: {
"default_retries": 0,
"default_retry_delay_seconds": 0
}
internal: {
"logging_level": "WARNING"
}
logging: {
"level": "INFO",
"config_path": "/home/prefect/.prefect/logging.yml",
"extra_loggers": [],
"log_prints": false,
"colors": true,
"markup": false,
"to_api": {
"enabled": true,
"batch_interval": 2,
"batch_size": 4000000,
"max_log_size": 1000000,
"when_missing_flow": "warn"
}
}
results: {
"default_serializer": "pickle",
"persist_by_default": false,
"default_storage_block": null,
"local_storage_path": "/home/prefect/.prefect/storage"
}
runner: {
"process_limit": 5,
"poll_frequency": 10,
"heartbeat_frequency": null,
"server": {
"enable": false,
"host": "localhost",
"port": 8080,
"log_level": "ERROR",
"missed_polls_tolerance": 2
}
}
server: {
"logging_level": "INFO",
"analytics_enabled": false,
"metrics_enabled": true,
"log_retryable_errors": true,
"register_blocks_on_start": true,
"memoize_block_auto_registration": true,
"memo_store_path": "/home/prefect/.prefect/memo_store.toml",
"deployment_schedule_max_scheduled_runs": 50,
"api": {
"auth_string": "**********",
"host": "0.0.0.0",
"port": 4200,
"base_path": "/api",
"default_limit": 200,
"keepalive_timeout": 70,
"csrf_protection_enabled": false,
"csrf_token_expiration": "PT1H",
"cors_allowed_origins": "*",
"cors_allowed_methods": "*",
"cors_allowed_headers": "*"
},
"concurrency": {
"lease_storage": "prefect_redis.lease_storage",
"initial_deployment_lease_duration": 300,
"maximum_concurrency_slot_wait_seconds": 30
},
"database": {
"sqlalchemy": {
"connect_args": {
"application_name": null,
"statement_cache_size": null,
"prepared_statement_cache_size": null,
"tls": {
"enabled": false,
"ca_file": null,
"cert_file": null,
"key_file": null,
"check_hostname": true
}
},
"pool_size": 5,
"pool_recycle": 3600,
"pool_timeout": 30,
"max_overflow": 10
},
"connection_url": "**********",
"driver": null,
"host": null,
"port": null,
"user": null,
"name": null,
"password": null,
"echo": false,
"migrate_on_start": false,
"timeout": 30,
"connection_timeout": 5
},
"deployments": {
"concurrency_slot_wait_seconds": 30
},
"docket": {
"name": "prefect-server",
"url": "<redis://prefect-redis-replication-master.prefect.svc.cluster.local:6379/0>"
},
"ephemeral": {
"enabled": true,
"startup_timeout_seconds": 20
},
"events": {
"stream_out_enabled": true,
"related_resource_cache_ttl": "PT5M",
"maximum_labels_per_resource": 500,
"maximum_related_resources": 100,
"maximum_size_bytes": 1500000,
"expired_bucket_buffer": "PT1M",
"proactive_granularity": "PT5S",
"retention_period": "P7D",
"maximum_websocket_backfill": "PT15M",
"websocket_backfill_page_size": 250,
"messaging_broker": "prefect_redis.messaging",
"messaging_cache": "prefect_redis.messaging",
"causal_ordering": "prefect_redis.ordering",
"maximum_event_name_length": 1024
},
"flow_run_graph": {
"max_nodes": 10000,
"max_artifacts": 10000
},
"logs": {
"stream_out_enabled": false,
"stream_publishing_enabled": false
},
"services": {
"cancellation_cleanup": {
"enabled": true,
"loop_seconds": 20
},
"event_persister": {
"enabled": true,
"batch_size": 20,
"read_batch_size": 1,
"flush_interval": 5,
"batch_size_delete": 10000
},
"event_logger": {
"enabled": true
},
"foreman": {
"enabled": true,
"loop_seconds": 15,
"inactivity_heartbeat_multiple": 3,
"fallback_heartbeat_interval_seconds": 30,
"deployment_last_polled_timeout_seconds": 60,
"work_queue_last_polled_timeout_seconds": 60
},
"late_runs": {
"enabled": true,
"loop_seconds": 5,
"after_seconds": "PT15S"
},
"scheduler": {
"enabled": true,
"loop_seconds": 60,
"deployment_batch_size": 100,
"max_runs": 100,
"min_runs": 3,
"max_scheduled_time": "P100D",
"min_scheduled_time": "PT1H",
"insert_batch_size": 500,
"recent_deployments_loop_seconds": 5
},
"pause_expirations": {
"enabled": true,
"loop_seconds": 5
},
"repossessor": {
"enabled": true,
"loop_seconds": 15
},
"task_run_recorder": {
"enabled": true,
"read_batch_size": 1
},
"triggers": {
"enabled": true,
"read_batch_size": 1,
"pg_notify_reconnect_interval_seconds": 10,
"pg_notify_heartbeat_interval_seconds": 5
}
},
"tasks": {
"tag_concurrency_slot_wait_seconds": 30,
"max_cache_key_length": 2000,
"scheduling": {
"max_scheduled_queue_size": 1000,
"max_retry_queue_size": 100,
"pending_task_timeout": "PT0S"
}
},
"ui": {
"enabled": true,
"api_url": "<dummy>",
"serve_base": "/",
"static_directory": "/ui_build",
"show_promotional_content": true
}
}
tasks: {
"refresh_cache": false,
"default_no_cache": false,
"disable_caching": false,
"default_retries": 0,
"default_retry_delay_seconds": 0,
"default_persist_result": null,
"runner": {
"thread_pool_max_workers": null,
"process_pool_max_workers": null
},
"scheduling": {
"default_storage_block": null,
"delete_failed_submissions": true
}
}
testing: {
"test_mode": false,
"unit_test_mode": false,
"unit_test_loop_debug": true,
"test_setting": "FOO"
}
worker: {
"heartbeat_seconds": 30,
"query_seconds": 10,
"prefetch_seconds": 10,
"webserver": {
"host": "0.0.0.0",
"port": 8080
}
}
ui_url:
silence_api_url_misconfiguration: falseMarvin
03/03/2026, 3:26 AMMarvin
03/03/2026, 3:26 AM鹿野孟城
03/03/2026, 3:27 AMhome: /home/prefect/.prefect
profiles_path: /home/prefect/.prefect/profiles.toml
debug_mode: false
api: {
"url": null,
"auth_string": null,
"key": null,
"tls_insecure_skip_verify": false,
"ssl_cert_file": null,
"enable_http2": false,
"request_timeout": 60
}
cli: {
"colors": true,
"prompt": null,
"wrap_lines": true
}
client: {
"max_retries": 5,
"retry_jitter_factor": 0.2,
"retry_extra_codes": [],
"csrf_support_enabled": true,
"custom_headers": {},
"metrics": {
"enabled": true,
"port": 4201
}
}
cloud: {
"api_url": "<https://api.prefect.cloud/api>",
"enable_orchestration_telemetry": true,
"max_log_size": 25000,
"ui_url": "<https://app.prefect.cloud>"
}
deployments: {
"default_work_pool_name": null,
"default_docker_build_namespace": null
}
experiments: {
"warn": true,
"plugins": {
"enabled": false,
"allow": [],
"deny": [],
"setup_timeout_seconds": 20,
"strict": false,
"safe_mode": false
}
}
flows: {
"default_retries": 0,
"default_retry_delay_seconds": 0
}
internal: {
"logging_level": "WARNING"
}
logging: {
"level": "INFO",
"config_path": "/home/prefect/.prefect/logging.yml",
"extra_loggers": [],
"log_prints": false,
"colors": true,
"markup": false,
"to_api": {
"enabled": true,
"batch_interval": 2,
"batch_size": 4000000,
"max_log_size": 1000000,
"when_missing_flow": "warn"
}
}
results: {
"default_serializer": "pickle",
"persist_by_default": false,
"default_storage_block": null,
"local_storage_path": "/home/prefect/.prefect/storage"
}
runner: {
"process_limit": 5,
"poll_frequency": 10,
"heartbeat_frequency": null,
"server": {
"enable": false,
"host": "localhost",
"port": 8080,
"log_level": "ERROR",
"missed_polls_tolerance": 2
}
}
server: {
"logging_level": "INFO",
"analytics_enabled": false,
"metrics_enabled": true,
"log_retryable_errors": true,
"register_blocks_on_start": true,
"memoize_block_auto_registration": true,
"memo_store_path": "/home/prefect/.prefect/memo_store.toml",
"deployment_schedule_max_scheduled_runs": 50,
"api": {
"auth_string": "**********",
"host": "0.0.0.0",
"port": 4200,
"base_path": "/api",
"default_limit": 200,
"keepalive_timeout": 70,
"csrf_protection_enabled": false,
"csrf_token_expiration": "PT1H",
"cors_allowed_origins": "*",
"cors_allowed_methods": "*",
"cors_allowed_headers": "*"
},
"concurrency": {
"lease_storage": "prefect_redis.lease_storage",
"initial_deployment_lease_duration": 300,
"maximum_concurrency_slot_wait_seconds": 30
},
"database": {
"sqlalchemy": {
"connect_args": {
"application_name": null,
"statement_cache_size": null,
"prepared_statement_cache_size": null,
"tls": {
"enabled": false,
"ca_file": null,
"cert_file": null,
"key_file": null,
"check_hostname": true
}
},
"pool_size": 5,
"pool_recycle": 3600,
"pool_timeout": 30,
"max_overflow": 10
},
"connection_url": "**********",
"driver": null,
"host": null,
"port": null,
"user": null,
"name": null,
"password": null,
"echo": false,
"migrate_on_start": false,
"timeout": 30,
"connection_timeout": 5
},
"deployments": {
"concurrency_slot_wait_seconds": 30
},
"docket": {
"name": "prefect-server",
"url": "<redis://prefect-redis-replication-master.prefect.svc.cluster.local:6379/0>"
},
"ephemeral": {
"enabled": true,
"startup_timeout_seconds": 20
},
"events": {
"stream_out_enabled": true,
"related_resource_cache_ttl": "PT5M",
"maximum_labels_per_resource": 500,
"maximum_related_resources": 100,
"maximum_size_bytes": 1500000,
"expired_bucket_buffer": "PT1M",
"proactive_granularity": "PT5S",
"retention_period": "P7D",
"maximum_websocket_backfill": "PT15M",
"websocket_backfill_page_size": 250,
"messaging_broker": "prefect_redis.messaging",
"messaging_cache": "prefect_redis.messaging",
"causal_ordering": "prefect_redis.ordering",
"maximum_event_name_length": 1024
},
"flow_run_graph": {
"max_nodes": 10000,
"max_artifacts": 10000
},
"logs": {
"stream_out_enabled": false,
"stream_publishing_enabled": false
},
"services": {
"cancellation_cleanup": {
"enabled": true,
"loop_seconds": 20
},
"event_persister": {
"enabled": true,
"batch_size": 20,
"read_batch_size": 1,
"flush_interval": 5,
"batch_size_delete": 10000
},
"event_logger": {
"enabled": true
},
"foreman": {
"enabled": true,
"loop_seconds": 15,
"inactivity_heartbeat_multiple": 3,
"fallback_heartbeat_interval_seconds": 30,
"deployment_last_polled_timeout_seconds": 60,
"work_queue_last_polled_timeout_seconds": 60
},
"late_runs": {
"enabled": true,
"loop_seconds": 5,
"after_seconds": "PT15S"
},
"scheduler": {
"enabled": true,
"loop_seconds": 60,
"deployment_batch_size": 100,
"max_runs": 100,
"min_runs": 3,
"max_scheduled_time": "P100D",
"min_scheduled_time": "PT1H",
"insert_batch_size": 500,
"recent_deployments_loop_seconds": 5
},
"pause_expirations": {
"enabled": true,
"loop_seconds": 5
},
"repossessor": {
"enabled": true,
"loop_seconds": 15
},
"task_run_recorder": {
"enabled": true,
"read_batch_size": 1
},
"triggers": {
"enabled": true,
"read_batch_size": 1,
"pg_notify_reconnect_interval_seconds": 10,
"pg_notify_heartbeat_interval_seconds": 5
}
},
"tasks": {
"tag_concurrency_slot_wait_seconds": 30,
"max_cache_key_length": 2000,
"scheduling": {
"max_scheduled_queue_size": 1000,
"max_retry_queue_size": 100,
"pending_task_timeout": "PT0S"
}
}
}Marvin
03/03/2026, 3:27 AMMarvin
03/03/2026, 3:29 AMprefect server database upgrade
- Kubernetes example:
kubectl exec -it deploy/<your-prefect-api-or-background-deploy> -- prefect server database upgrade
- Or enable auto-migrate on startup going forward:
PREFECT_SERVER_DATABASE_MIGRATE_ON_START=true
2) Verify tables and event ingestion
- Check tables and row count:
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' AND table_name IN ('events', 'event_resources');
SELECT COUNT(*) FROM events;
- Post a test event:
curl -X POST http://<api-host>:<port>/api/events \
-H "Content-Type: application/json" \
-d '[{
"occurred": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
"event": "diagnostic.test",
"resource": {"prefect.resource.id": "diagnostic/test"}
}]'
- Re-check:
SELECT COUNT(*) FROM events;
- And via API:
curl -X POST http://<api-host>:<port>/api/events/filter \
-H "Content-Type: application/json" \
-d '{"filter": {"events": ["*"]}, "limit": 5}'
3) Ensure the feed can stream to the UI
- Your config has events.stream_out_enabled: true. If the DB now contains events but the UI feed is still blank, check the browser Network tab for a WebSocket to /api/events/out. If it fails, update your ingress to allow WebSocket upgrades and long-lived connections. Example for NGINX:
location /api/events/out {
proxy_pass http://<prefect-api-service>;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
Optional diagnostics
- Make sure the persister is actually starting after restart:
kubectl logs deploy/<your-prefect-api-or-background-deploy> | egrep -i "event_persister|events.services|Distributor|websocket"
- Temporarily increase verbosity to catch errors:
PREFECT_LOGGING_LEVEL=DEBUG
Given your settings (Redis broker/ordering enabled, stream_out true, event_logger true), my money is on the missing migrations. Run the upgrade and let me know:
- Whether the tables now exist
- The result of the test-event POST and subsequent queries
- If the UI WebSocket shows as connected in your browser
If anything still looks off, please share the result of those checks and I’ll dig right in.