Skip to content

perf(cache): LRU eviction, store-hit metric, peek() probes, bigger char cap - #177

Merged
VortexUK merged 1 commit into
mainfrom
fix/cache-metrics-lru
Jul 22, 2026
Merged

perf(cache): LRU eviction, store-hit metric, peek() probes, bigger char cap#177
VortexUK merged 1 commit into
mainfrom
fix/cache-metrics-lru

Conversation

@VortexUK

Copy link
Copy Markdown
Owner

Summary

Follow-up to the Grafana cache investigation: hit ratios read ~4% with the character cache pinned at its 500 cap, but most "misses" were false positives — served instantly from census_store, which the metrics couldn't see.

  • cache_store_hits_total{cache}: new counter incremented where a memory miss is served from the durable census_store (character / guild / aa / gear-sets read paths). Dashboards can now split misses into store-absorbed vs real Census fetches (rate(cache_misses_total) − rate(cache_store_hits_total) ≈ true fetch pressure).
  • LRU eviction: TTLCache eviction was FIFO-by-insert — a guild-roster flood evicted hot entries as readily as cold ones. get/get_stale and overwrites now move entries to the back of the eviction queue.
  • peek(): metric-free, side-effect-free read for opportunistic probes. /api/characters/lookup's 50-name enrichment sweep uses it, so probe misses (which never fall through to anything) stop polluting hit ratios and LRU order.
  • character_cache maxsize 500 → 2000: rosters + the startup prewarm exceed 500 combined, cycling the cache; entries are a few KB (~10–20 MB worst case).

Testing

9 new TTLCache tests (LRU survival on read/overwrite, peek fresh+stale semantics without metrics or LRU side effects, hard-expiry, store-hit counter) + lookup-endpoint mocks updated. Full suite 1611 passed, pyright clean. Frontend untouched.

🤖 Generated with Claude Code

…ar cap

The Grafana cache panels showed ~4% hit ratios with the character cache
pinned at its 500 cap. Investigation: most "misses" were served instantly
by census_store (invisible to the metrics), bulk lookup probes counted
misses they never act on, and eviction was FIFO-by-insert so roster
floods cycled out the hot working set.

- cache_store_hits_total{cache}: incremented where a memory miss is
  served from the durable census_store (character/guild/aa/gear-sets) —
  dashboards can now split misses into store-absorbed vs Census fetches.
- TTLCache eviction is LRU-by-access: get/get_stale and overwrites move
  the entry to the back of the eviction queue.
- peek(): metric-free, side-effect-free read for opportunistic probes;
  /api/characters/lookup's 50-name sweep uses it so enrichment probes
  stop polluting hit ratios and LRU order.
- character_cache maxsize 500 -> 2000 (guild rosters + startup prewarm
  exceeded 500 combined; entries are a few KB, ~10-20 MB worst case).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@VortexUK
VortexUK merged commit 7bc54eb into main Jul 22, 2026
6 checks passed
@VortexUK
VortexUK deleted the fix/cache-metrics-lru branch July 22, 2026 17:23
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