Dashboard Performance Optimization & Issue Resolution¶
This document summarizes the resolution of the performance bottlenecks that caused high loading times (and the "Loading sites..." hang) on the dashboard page.
1. Problem Description¶
On mounting the dashboard page, the React client initiates three parallel requests and polls the system pulse endpoint once every second: 1. GET /api/v1/sites/ 2. GET /api/v1/devices/device 3. GET /api/v1/ai/anomalies 4. GET /api/v1/health/system-pulse (every 1s)
Previously, each of these endpoints suffered from critical resource contention issues: * \(N+1\) Database Query Patterns: Looping over list objects and fetching permissions or related children individually. * Process Monitor Overhead: The 1-second system pulse check scanned every single running system process via psutil.process_iter() to find the Ollama service, blocking the API thread.
2. Changed Files¶
Phase 1: Database Optimizations (+140, -70 lines)¶
| File Path | Description |
|---|---|
auth_utils.py | Added bulk authorization helper get_accessible_site_ids to retrieve a user's accessible site database IDs in a single batched query instead of looping. |
SitesEndpoint.py | Updated list_sites() to use the new bulk helper, and batch fetched all device records for the retrieved sites in one query instead of querying inside the loop. |
DevicesEndpoints.py | Updated list_device() to filter devices using the batch helper. |
AIEndpoint.py | Refactored get_system_anomalies() to query DeviceMetrics and HealthCheck records in bulk using window functions, and deferred session.commit() to happen once after the loop. |
Phase 2: Process Monitor Optimization (+35, -10 lines)¶
| File Path | Description |
|---|---|
HealthEndpoint.py | Implemented a PID cache (_ollama_pids_cache) and scan throttling (max once per 10s on cache miss) in _get_homepot_resource_usage(), replacing the frequent full-system process iteration checks. |
3. Detailed Fix Resolution¶
Bulk Site Access Filtering¶
We replaced sequential loop evaluations with a batched query logic:
def get_accessible_site_ids(db_user: User, db: Session, minimum_role: str = "viewer") -> Optional[set[int]]:
if db_user.is_admin:
return None
# Retrieves all accessible site IDs matching tenant or site-level permissions in bulk...
AI Anomalies SQL Window Functions¶
Instead of querying metrics and health checks per device inside the loop, we used window queries:
# Batch retrieve latest metrics
metrics_subq = (
select(DeviceMetrics, func.row_number().over(
partition_by=DeviceMetrics.device_id,
order_by=DeviceMetrics.timestamp.desc()
).label("rn"))
.where(DeviceMetrics.device_id.in_(device_ids_to_check))
.subquery()
)
Health Scan Cache & Throttling¶
Checking cached Ollama process info directly instead of searching all running tasks:
# If cache is active, verify process is still running and grab metrics.
# If empty, perform psutil.process_iter() but throttle to once every 10 seconds.
4. Verification & Testing¶
All backend unit and integration test suites passed successfully:
pytest tests/test_devices_by_site.py tests/test_ai_db_integration.py tests/test_ai_integration.py tests/test_device_metrics.py
21 passed (no regressions). * Observed Latency Improvement: * DB Endpoint latency drops: from \(O(N)\) database query roundtrips to \(O(1)\). * /health/system-pulse response times: from ~500ms+ down to <10ms, resolving Dashboard blockages.