refactor(e5): deferred review-tail (backend) — enrich off request path, reuse, tests
Address the deep-review's deferred backend items so E5 is review-complete: - person-enrich OFF the request path (ABUSE finding): person_detail no longer makes the TMDB call inline (even bounded to 8s it sat on the serve thread, un-throttled, demo-reachable — it violated the module's "no live TMDB call at serve time" invariant). It now schedules a FastAPI BackgroundTask (people._enrich_person_bg, fresh session, best-effort) after the response; the first open serves the row as-is and the bio lands by the next open. The inline try/rollback recovery is gone with it. - reuse: a shared tmdb.resolve_library_guids owns the collision-safe guid→library bucketing (movie vs tv ids are independent sequences) that resolve_recs and people._resolve_known_for each hand-duplicated; a new rollup.item_state_map dedups the "PlexState-by-item_id" fetch across the person + discover paths. - test gaps: enrich_batch transient TmdbError leaves the watermark NULL to retry; guid_to_tmdb_id resolves a tvdb source + tv media_type via /find's tv_results; _continue_watching includes a NULL-status started movie and excludes a hidden one; /api/search/youtube returns 422 (not 5xx) when ingest fails (route-level, B-core-1). Backend lane 403 → 413, ruff clean. No migration; serve contracts unchanged.
This commit is contained in:
@@ -37,19 +37,8 @@ def _scope_libs(db: Session, scope: str) -> tuple[list[int], list[int]]:
|
||||
)
|
||||
|
||||
|
||||
def _movie_states(db: Session, uid: int, items: list[PlexItem]) -> dict[int, PlexState]:
|
||||
"""One batched fetch of the user's watch-state for a set of movies (avoids a per-card query)."""
|
||||
ids = [it.id for it in items]
|
||||
if not ids:
|
||||
return {}
|
||||
rows = db.execute(
|
||||
select(PlexState).where(PlexState.user_id == uid, PlexState.item_id.in_(ids))
|
||||
).scalars().all()
|
||||
return {r.item_id: r for r in rows}
|
||||
|
||||
|
||||
def _movie_cards(db: Session, uid: int, items: list[PlexItem]) -> list[dict]:
|
||||
sts = _movie_states(db, uid, items)
|
||||
sts = rollup.item_state_map(db, uid, [it.id for it in items])
|
||||
return [movie_card(it, sts.get(it.id)) for it in items]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user