Skip to content

perf: /api/v2/videos/list scans and parses the processed-video cache on the event loop #1287

Description

@groupthinking

Defect

GET /api/v2/videos/list is declared async def, but its entire body is synchronous
filesystem work executed directly on the event loop
(src/youtube_extension/backend/real_api_endpoints.py):

  • cache_dir.exists() — a blocking stat
  • cache_dir.glob("*_processed.json") — a blocking directory walk
  • one blocking open() + json.load() per cached video

There is no upper bound on the number of cache entries. The handler never awaits, so
from the moment the request is dispatched until the listing is built, the event loop
cannot run any other task: no other request is served, no heartbeat fires, no timeout
is honoured. The stall grows linearly with the number of processed videos, which grows
monotonically over the lifetime of the deployment.

Measured on a 2,000-entry cache with realistic transcript and analysis payloads, the
handler stalls the loop for ~176–215 ms in a single call.

Expected

The cache scan runs in a worker thread, matching the pattern already established across
this codebase (#1194, #1196, #1228, #1233, #1240, #1245, #1251): a module-level *_sync
helper invoked via await asyncio.to_thread(...).

Acceptance criteria

  • The blocking scan no longer executes on the event loop thread.
  • Response payload is unchanged: same 12 keys per entry, same newest-first ordering,
    same silent-skip behaviour for corrupt entries, same empty-list result for a
    missing cache directory, same [] on unexpected error.
  • A regression test asserts the scan runs off the loop thread and fails against the
    pre-change source.
  • All existing tests in tests/unit/test_real_api_endpoints.py pass unmodified.

Out of scope

  • GET /api/v2/videos/{video_id} (get_video_analysis), which has the same blocking
    open() + json.load() defect. Separate issue.
  • clear_processing_cache, which calls blocking shutil.rmtree() + mkdir().
    Separate issue.
  • real_video_processor.py cache handling, already claimed by open PR perf: offload cache-directory scan off the event loop (#1231) #1237.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions