Skip to content

fix: thumbnail resilience for large collections (#67) - #74

Merged
danmunz merged 2 commits into
mainfrom
fix/thumbnail-resilience
Jun 2, 2026
Merged

fix: thumbnail resilience for large collections (#67)#74
danmunz merged 2 commits into
mainfrom
fix/thumbnail-resilience

Conversation

@danmunz

@danmunz danmunz commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Third round of fixes for #67 — thumbnail loading failures on large collections (525+ artworks).

What changed

Backend (server.py)

  • Startup prefetch: On boot, fetches the artwork list and pre-warms the thumbnail cache in the background. Auto-retries every 5 minutes until all thumbnails are cached, so the cache fills gradually even with an intermittently unreachable TV.
  • Fail-fast batch call: get_thumbnail_list now uses attempts=1 (~18s max) instead of the default 3 (~54s). Trips the circuit breaker faster.
  • Shorter prefetch timeout: Background fetches use a 5s timeout instead of 10s, halving the worst-case lock hold time and giving user operations (select, display) more frequent windows to acquire the lock.
  • POST /api/thumbnails/retry endpoint: Resets the circuit breaker and schedules a fresh server-side prefetch for specified content IDs.
  • Race condition fix: _thumb_prefetch_running is now set before create_task() at all 4 spawn sites, preventing duplicate prefetch tasks from being spawned between scheduling and execution.

Frontend (index.html)

  • "Retry All" button: When thumbnail loading completes with errors, the progress bar shows a count of failed thumbnails and a "Retry All" button instead of disappearing. Clicking it resets the circuit breaker server-side, kicks a fresh prefetch, and re-requests all failed thumbnails.

Tests

  • Added test for the retry endpoint (circuit breaker reset + prefetch scheduling).

Failure modes addressed

# Failure Mode Fix
1 First request blocks ~54s attempts=1 → max ~18s
2 Prefetch aborts after 5 failures, 520 thumbs stuck Auto-retry every 5 min + "Retry All" button
3 Race: duplicate prefetch tasks Set flag before create_task at all spawn sites
4 Prefetch holds lock 10s per attempt 5s prefetch timeout reduces lock contention
5 60-second circuit breaker failure cycle Retry endpoint resets breaker; startup prefetch bypasses it

How it works for a user with 525 artworks

  1. Server boots → waits 5s → starts background prefetch of uncached thumbnails
  2. User opens page → cached thumbnails appear instantly, uncached ones fail fast (~18s)
  3. Progress bar shows "375 thumbnails failed" + Retry All button
  4. Meanwhile server keeps grinding through thumbnails in background, auto-retrying every 5 min
  5. User clicks Retry All → newly cached thumbnails appear, remaining failures show button again
  6. Over 30-60 min of uptime, cache fills completely; next restart starts warm

Fixes #67

- Startup prefetch: warm thumbnail cache in background on boot, auto-retry
  every 5 min until all thumbnails are cached
- Fail-fast batch call: attempts=1 on get_thumbnail_list (~18s vs ~54s)
- Shorter prefetch timeout: 5s instead of 10s to reduce lock contention
  during background fetches, giving user operations more frequent windows
- Retry All button: frontend shows button when loading completes with
  errors, resets circuit breaker and kicks fresh server-side prefetch
- POST /api/thumbnails/retry endpoint: resets circuit breaker and
  schedules background prefetch for specified content IDs
- Race condition fix: set _thumb_prefetch_running before create_task at
  all spawn sites to prevent duplicate prefetch tasks

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f24b59b6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server.py Outdated
Comment on lines +522 to +523
if consecutive_failures >= _PREFETCH_MAX_FAILURES:
remaining_ids = content_ids[i:]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include failed IDs in startup prefetch retries

When the startup prefetch aborts after _PREFETCH_MAX_FAILURES consecutive failures, this retry list starts at the next unattempted ID, so the five IDs that just failed are omitted from every scheduled startup retry. If the TV is temporarily unreachable for those first attempts, the auto-retry loop can eventually cache later thumbnails while permanently leaving the initially failed thumbnails behind until a user explicitly retries them.

Useful? React with 👍 / 👎.

Comment thread server.py
Comment on lines +592 to +594
except Exception as e:
log.warning("Startup prefetch: could not fetch artwork list: %s", e)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retry startup prefetch after artwork-list failures

If the TV is unreachable during this initial _refresh_art_cache call, _startup_prefetch returns and nothing schedules another attempt, even though lifespan only starts this task once. In the common intermittent-TV-at-boot case, the new background cache warmer never starts, so large collections still depend on the user's page load/retry flow instead of recovering automatically.

Useful? React with 👍 / 👎.

…t failure

Address Codex review comments on PR #74:

1. When prefetch aborts after consecutive failures, the IDs that actually
   failed were excluded from the retry list (only unattempted IDs were
   included). Now failed_ids are tracked separately and prepended to the
   retry list so they get another chance on the next cycle.

2. If _startup_prefetch fails to fetch the artwork list (TV unreachable
   at boot), it now schedules a retry after _PREFETCH_RETRY_COOLDOWN
   seconds instead of silently giving up. This ensures the background
   cache warmer eventually starts even with intermittent TV connectivity.
@Nitrowolf

Copy link
Copy Markdown

I will let this run overnight and see how things fare in the morning.

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

Labels

None yet

2 participants