Skip to content

perf(espn): remember settled day chunks between window refreshes - #754

Open
ChuckBuilds wants to merge 1 commit into
mainfrom
perf/espn-settled-chunk-cache
Open

ChuckBuilds wants to merge 1 commit into
mainfrom
perf/espn-settled-chunk-cache

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Summary

ESPN still rejects dates= ranges, so each scoreboard's Recent/Upcoming window (14 days back, 7 ahead) costs 22 day requests. The window is re-fetched in full on every hourly update, including the 12+ days whose games finished long ago. src/common/espn_dates._fetch_one_chunk now remembers a chunk once its last day is at least 3 UTC days old ("settled"), for 24 hours, so the hourly refresh only goes to ESPN for days that can still change.

  • Settled means 3 UTC days back. That leaves a full day of margin past late West-coast games and ESPN's Eastern-date filing. A rare later correction (say a suspended game completed) shows up within the 24 h TTL.
  • Storage: stored as zlib-compressed JSON (~13x smaller than the body). Every hit is parsed afresh, so callers never share objects. Bounded at 512 entries / 8 MB, with locking.
  • Key: URL + the other params (e.g. groups=80 for FBS) + the chunk.
  • Never stored: failed chunks and capped months (500 events).
  • Coverage: both chunk paths go through _fetch_one_chunk (fetch_espn_scoreboard and BackgroundDataService._fetch_in_date_chunks), so every scoreboard gets it. It sits in front of feat(fetch): one ESPN scoreboard cache key and a max-age response cache (fetch service stage 2) #728's response cache, whose 10-minute ceiling the hourly refresh always misses.

Type of change

  • Bug fix (performance / network)

Test plan

  • Against live ESPN: a second refresh of the five hdpi windows went from 111 requests / 10.18 MB to 50 requests / 3.23 MB, with identical event ids. The memory held 60 entries in 585 KB.
  • Ran on a real Raspberry Pi with hardware: hdpi (Pi 4), 74-min windows from a fresh restart, each containing an hourly window refresh. ESPN traffic was 26.8 → 16.0 MB/h (−40%), requests 482 → 363/h. Three main windows that night ran 24.9–27.1 MB/h. No frame-timing change. RSS in this branch's window was 20–60 MB above the main window just before it, which is inside the range of all four main windows that night apart from two marks (380/384 vs ≤367 MB). The cache itself is capped at 8 MB, so I read that as noise, but it's one window, so it's worth watching.
  • Ran the test suite (pytest): 8 new tests (only unsettled days re-asked, same events and order, a hit is a copy, params in the key, 24 h expiry, failures not stored, capped month not stored, memory bound, single-day requests untouched).
  • Rebased onto feat(fetch): one ESPN scoreboard cache key and a max-age response cache (fetch service stage 2) #728. The day-cache lookup sits in front of the new cache_max_age pass-through. test/conftest.py now pins espn_dates._utc_today to 2000-01-01 for every test, so no fixture date counts as settled unless a test pins "today" itself. Without that, two test_background_data_service_espn_ranges tests asking for September 2026 twice started failing on 2026-10-03, once September became settled.

Notes for reviewer

The scoreboards also download each expiring window twice. The managers submit the background fetch and then immediately call _get_weeks_data() for the same window, and the fetch service doesn't merge the two. That's a plugin-side fix in every sports lineage, not part of this PR. Together with it, a window refresh would drop from ~2×10 MB to ~3 MB.

🤖 Generated with Claude Code

Since ESPN started rejecting date ranges, every scoreboard's hourly
Recent/Upcoming refresh re-asks its 22-day window (14 back, 7 ahead) one
day at a time. Measured on hdpi 2026-10-02 (NFL, college football, MLB,
college baseball, NHL): the hourly refresh was ~270 of 321 ESPN requests
and ~21 of 24.6MB in the hour. Days that ended three or more days ago
cannot change, and they were 68% of the window's bytes (6.9 of 10.2MB).

_fetch_one_chunk now keeps a settled chunk (last day <= UTC today - 3) in
memory for 24h as zlib-compressed JSON, keyed by URL, the other params
and the chunk, and answers it from there. Both range paths go through it:
fetch_espn_scoreboard and BackgroundDataService._fetch_in_date_chunks.
Each hit is parsed afresh, failed and capped chunks are not stored, and
the memory is bounded (512 entries / 8MB compressed). Against live ESPN,
a second refresh of the five hdpi windows went from 111 requests and
10.18MB to 50 requests and 3.23MB with identical events; the memory held
60 entries in 585KB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 47 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 98085968-7d0f-4479-8d93-15062771e78a
📥 Commits

Reviewing files that changed from the base of the PR and between 2236ff3 and 3ea1fd4.

📒 Files selected for processing (3)
  • src/common/espn_dates.py
  • test/conftest.py
  • test/test_espn_dates.py
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 28 complexity

Metric Results
Complexity 28

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant