Problem
PerformanceMonitor (src/youtube_extension/backend/services/performance_monitor.py) uses the fully synchronous sqlite3 driver directly inside six async def methods:
| Line |
Method |
| 274 |
_store_metric |
| 357 |
_store_alert |
| 504 |
_basic_cleanup |
| 566 |
get_current_performance_summary |
| 662 |
_get_recent_metrics_summary |
| 802 |
_store_benchmark_result |
Each performs sqlite3.connect(...) → statement → commit() → close(). commit() fsyncs. All of it runs on the event loop, so no other coroutine can be scheduled while the write is in flight.
Reachability evidence
Not speculative — this is on a live request path:
youtube_extension.backend.services.performance_monitor is in the transitive import closure of the production entrypoint youtube_extension.main:app (root Dockerfile:93).
src/youtube_extension/backend/api/v1/router.py:69 — from ...services.performance_monitor import PerformanceMonitor
router.py:1165 and router.py:1183 — await performance_monitor.record_metric(...)
record_metric (L231) calls await self._store_metric(metric) (L261) unconditionally — there is no sampling or enable flag.
Additional live callers: memory_manager.py:472/475, load_balancer.py:381, database_optimizer.py:49.
Proposed fix
Move each method's database work into a nested synchronous function dispatched via await asyncio.to_thread(...). SQL text, transaction boundaries, return values and error handling stay identical.
Leave _init_database (L127) alone — it is synchronous and called from __init__, so it never runs on the loop.
Acceptance criteria
Problem
PerformanceMonitor(src/youtube_extension/backend/services/performance_monitor.py) uses the fully synchronoussqlite3driver directly inside sixasync defmethods:_store_metric_store_alert_basic_cleanupget_current_performance_summary_get_recent_metrics_summary_store_benchmark_resultEach performs
sqlite3.connect(...)→ statement →commit()→close().commit()fsyncs. All of it runs on the event loop, so no other coroutine can be scheduled while the write is in flight.Reachability evidence
Not speculative — this is on a live request path:
youtube_extension.backend.services.performance_monitoris in the transitive import closure of the production entrypointyoutube_extension.main:app(rootDockerfile:93).src/youtube_extension/backend/api/v1/router.py:69—from ...services.performance_monitor import PerformanceMonitorrouter.py:1165androuter.py:1183—await performance_monitor.record_metric(...)record_metric(L231) callsawait self._store_metric(metric)(L261) unconditionally — there is no sampling or enable flag.Additional live callers:
memory_manager.py:472/475,load_balancer.py:381,database_optimizer.py:49.Proposed fix
Move each method's database work into a nested synchronous function dispatched via
await asyncio.to_thread(...). SQL text, transaction boundaries, return values and error handling stay identical.Leave
_init_database(L127) alone — it is synchronous and called from__init__, so it never runs on the loop.Acceptance criteria
async defsqlite call sites dispatched off-looptests/unit/test_performance_monitor.pytests pass with zero test editsmain