Skip to content

Cache Similar Jobs tab with stale-while-revalidate#9669

Draft
camd wants to merge 1 commit into
masterfrom
camd/similar-jobs-cache-swr
Draft

Cache Similar Jobs tab with stale-while-revalidate#9669
camd wants to merge 1 commit into
masterfrom
camd/similar-jobs-cache-swr

Conversation

@camd

@camd camd commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Problem

The Similar Jobs tab in the job-details panel is unmounted by react-tabs when inactive and remounted on return, which resets its state (list, "Show previous jobs" pagination, selected job, and the "Exclude successful jobs" filter) and refetches everything — page 1 of similar jobs, the push data, and the auto-selected job's detail (JobModel.get + text-log-errors). Switching back felt like a full reload and lost the user's place.

Unlike bug suggestions, Similar Jobs is a live query over the Job table: new jobs of the same type land on nearly every push, and statuses of already-listed jobs change (a running job finishes, another user classifies/retriggers). That list is its own fetch, not fed by the main job-view poll, so it never self-updates today.

Change

Add a per-session snapshot cache (similarJobsCache) keyed by the investigated jobId, and restore it on mount, then stale-while-revalidate:

  • Instant restore of the full tab state (list, loaded pages, selected job + its detail, filter) with no spinner.
  • Background revalidate when the snapshot's list is older than a 30s dedup window: refetch all loaded pages in one request and refresh the selected job's detail, then swap the fresh data in — picking up newly-arrived same-type jobs and status changes on listed rows.
  • Dedup window (30s) avoids refetching on rapid tab toggling.
  • Mount guard lets a revalidate that resolves after the user tabs away update the cache while skipping setState.
  • Bounded to 50 jobIds, evicting the oldest.

The tab's fetch logic is refactored into reusable fetchAndEnrich (page range) and fetchJobDetail helpers.

Out of scope / unaffected

The left job-info panel is untouched: the selected job's own status and log-parse status still update live via useJobDetails + the push poll (its effect re-runs on selectedJob.state/.result/.failure_classification_id). Only the other jobs listed in the Similar Jobs tab live in the snapshot, which is exactly what the revalidate refreshes. Continuous polling while the tab is visible is intentionally out of scope (revalidate-on-open only).

Tests

  • similarJobsCache_test.js — store/retrieve, eviction, recency refresh, freshness window.
  • SimilarJobsTab_test.jsx — cache-miss fetch+render, fresh-hit hydrate with no revalidate (dedup), stale-hit hydrate + background revalidate swap.

Note

Not yet driven in a real browser (needs a dev server + a job with similar-job history); the interaction flows are best confirmed with a live smoke test.

The Similar Jobs tab is unmounted by react-tabs when inactive and remounted on
return, which reset the list, pagination, selected job, and filter and refetched
everything (page 1 + push data + the auto-selected job's detail). Switching back
felt like a full reload and lost the user's place.

Add a per-session snapshot cache keyed by the investigated jobId and restore it
on mount, then stale-while-revalidate:

- Restore the full tab state instantly (list, loaded pages, selected job and its
  detail, filter) with no spinner.
- If the snapshot's list was fetched more than 30s ago, revalidate in the
  background: refetch all loaded pages in one request and refresh the selected
  job's detail, then swap the fresh data in. This picks up newly-arrived
  same-type jobs and status changes on already-listed jobs.
- A 30s dedup window avoids refetching on rapid tab toggling.
- A mount guard lets a revalidate that resolves after the user tabs away update
  the cache while skipping setState.
- Bounded to 50 jobIds, evicting the oldest.

The tab's fetch logic is refactored into reusable fetchAndEnrich (page range) and
fetchJobDetail helpers. The left job-info panel is unaffected: the selected job's
own status and log-parse status still update live via useJobDetails and the push
poll.

Add unit tests for the cache (store/evict/recency/freshness) and the tab
(cache-miss fetch, fresh-hit dedup, stale-hit background revalidate).
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.54545% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.77%. Comparing base (740daac) to head (6f27069).

Files with missing lines Patch % Lines
ui/job-view/details/tabs/SimilarJobsTab.jsx 82.47% 15 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9669      +/-   ##
==========================================
+ Coverage   82.59%   82.77%   +0.17%     
==========================================
  Files         622      623       +1     
  Lines       36580    36647      +67     
  Branches     3279     3353      +74     
==========================================
+ Hits        30213    30334     +121     
+ Misses       6217     5929     -288     
- Partials      150      384     +234     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants