Skip to content

perf: serve video-detail cache entries as raw bytes, dropping the GIL-held parse - #1371

Merged
groupthinking merged 1 commit into
mainfrom
perf-jsonload-parse-still-stalls-the-event-loop-3-msmb-grv-282-9c4a
Aug 4, 2026
Merged

perf: serve video-detail cache entries as raw bytes, dropping the GIL-held parse#1371
groupthinking merged 1 commit into
mainfrom
perf-jsonload-parse-still-stalls-the-event-loop-3-msmb-grv-282-9c4a

Conversation

@groupthinking

Copy link
Copy Markdown
Owner

Canonical issue

Closes #1306

Outcome

GET /api/v2/videos/{video_id} no longer stalls the event loop in proportion to payload size. The handler only ever returned the parsed cache entry verbatim, so _read_video_analysis_sync now returns the entry's raw JSON bytes (read() releases the GIL) and the handler streams them back in a Response. This removes both the GIL-held json.load (~3 ms/MB, only relocated by #1304) and FastAPI's on-loop re-serialisation of the parsed dict, which paid the same size-proportional cost a second time.

Entries at or below _VALIDATION_MAX_BYTES (2 MiB — ~13× a typical one-hour transcript) are still parse-validated off-loop, so damaged entries keep surfacing as 500s. That threshold is the loop-stall bound: ~6 ms worst case, independent of video duration. Larger entries skip validation; the writer publishes atomically (temp file + os.replace), so a torn entry cannot be observed — only out-of-band corruption of an oversized entry would reach a client unflagged, accepted in exchange for the bounded stall.

The warm-cache regression disclosed in #1304 (executor hop costing more than the deferred 0.4 ms parse) is resolved by removing the parse and the on-loop re-serialisation outright; the fixed ~0.5 ms dispatch hop remains, deliberately, as insurance against unbounded filesystem latency.

Scope

  • Included: _read_video_analysis_sync, the /api/v2/videos/{video_id} handler, and their tests. The characterisation test test_parse_still_stalls_the_loop_in_proportion_to_payload is replaced by its successor test_read_stall_no_longer_scales_with_payload, self-calibrated against json.loads of the same payload on the runner.
  • Explicitly excluded: real_video_processor.py (held by perf: offload cache-directory scan off the event loop (#1231) #1237) — the entry-size cause (persisting the full transcript) is untouched.

Risk

  • Risk level: low
  • Failure mode: the response body is now the cache entry byte-for-byte instead of a re-serialised copy (semantically identical JSON; formatting/whitespace may differ). A corrupt entry above 2 MiB would be served verbatim instead of returning a 500.
  • Rollback: revert the commit; the endpoint returns to parse-and-re-serialise.

Verification

  • Focused tests: pytest tests/unit/test_real_api_endpoints.py — 107 passed at ec45eed, including new coverage for byte-for-byte passthrough, the inclusive validation boundary, oversized unvalidated entries, and the bounded-stall characterisation test (run 5× for flake resistance)
  • Required CI
  • Review threads resolved

Ruff/black were checked on the changed files; remaining findings are pre-existing in untouched regions.

Production evidence

Not applicable — backend perf change verified by the loop-gap characterisation test, which measures the stall directly against the old behaviour (json.loads of the same payload).

Agent provenance

Agent-authored via Linear agent session; run metadata is recorded in the linked Linear issue (GRV-282, agent session 36eebe27).

…-held parse

The single-entry cache read was offloaded to a worker thread in #1304, but
json.load holds the GIL (~3 ms/MB), so the parse still stalled the event loop
in proportion to payload size -- which is unbounded, since entries embed the
full transcript. FastAPI then re-serialised the parsed dict on the loop,
paying the same size-proportional cost a second time.

The handler only ever returned the parsed payload verbatim, so stop parsing:
_read_video_analysis_sync now returns the entry's raw JSON bytes (read()
releases the GIL) and the handler streams them back in a Response. Entries at
or below _VALIDATION_MAX_BYTES (2 MiB) are still parse-validated off-loop so
damaged entries keep surfacing as 500s; that threshold is the loop-stall
bound (~6 ms), independent of video duration. Larger entries skip validation
-- the writer publishes atomically via temp file + os.replace, so torn
entries cannot be observed.

The warm-cache regression from #1304 (executor hop costing more than the
deferred parse) is addressed by removing the parse and the on-loop
re-serialisation outright; the fixed ~0.5 ms hop remains as insurance against
unbounded filesystem latency.

The characterisation test pinning the old proportional stall is replaced by
its successor: the raw read must now stall the loop for a small fraction of
what parsing the same payload does, self-calibrated against json.loads on the
runner itself.

Generated with [Linear](https://linear.app/myxstack/issue/GRV-282/perf-jsonload-parse-still-stalls-the-event-loop-3-msmb-on-video-detail#agent-session-36eebe27)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@linear-code

linear-code Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

GRV-282

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Canceled Canceled v0 Aug 4, 2026 6:17am

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • [‘architecture-gap’, ‘bug’, ‘ci-cd’, ‘ci/cd’, ‘copilot-rabbit’, ‘documentation’, ‘duplicate’, ‘enhancement’, ‘frontend’, ‘github_actions’, ‘good first issue’, ‘help wanted’, ‘high-priority’, ‘invalid’, ‘javascript’, ‘ml-model’, ‘needs-triage’, ‘pipeline-critical’, ‘placeholder-code’, ‘priority:high’, ‘python’, ‘python:uv’, ‘question’, ‘styling’, ‘tests’, ‘v0’]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d79aef2e-3f84-4a39-a6ce-ae2acfa0227a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the python label Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA ec45eed.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "collection_errors": [
      "incomplete_linked_issue_contract",
      "missing_intent_snapshot",
      "missing_agent_run_id",
      "missing_agent_login"
    ],
    "invalid_fields": [
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

@groupthinking
groupthinking requested a balanced review from Copilot August 4, 2026 06:20
@linear-code
linear-code Bot marked this pull request as ready for review August 4, 2026 06:20
@groupthinking
groupthinking merged commit 40a8860 into main Aug 4, 2026
40 of 45 checks passed
@groupthinking
groupthinking deleted the perf-jsonload-parse-still-stalls-the-event-loop-3-msmb-grv-282-9c4a branch August 4, 2026 06:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Optimizes video-detail cache responses by eliminating payload-sized parsing and re-serialization from the request path.

Changes:

  • Returns cached JSON as raw bytes with bounded validation.
  • Serves bytes directly as an application/json response.
  • Adds regression and boundary coverage for the new behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/youtube_extension/backend/real_api_endpoints.py Implements validated raw-byte cache passthrough.
tests/unit/test_real_api_endpoints.py Tests passthrough, validation boundaries, and loop responsiveness.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: json.load parse still stalls the event loop (~3 ms/MB) on video-detail read

2 participants