Skip to content

fix(cache): route_cache and depends.py caches now bounded - #14

Merged
magi8101 merged 1 commit into
mainfrom
fix/cache-eviction-issue-8
Sep 6, 2026
Merged

magi8101 merged 1 commit into
mainfrom
fix/cache-eviction-issue-8

Conversation

@magi8101

@magi8101 magi8101 commented Sep 6, 2026

Copy link
Copy Markdown
Member

Fixes #8. Router.route_cache had a CachedRoute.is_valid()/ttl meant to gate freshness but nothing ever called it, and nothing pruned by size either — a dynamic route like /users/{id} got one permanent CachedRoute per distinct id ever requested. depends.py's three id(func)-keyed caches had the same shape of bug (cleanup_caches() existed for exactly this but was itself deleted as dead code in #9, since nothing called it).

Both now prune on write, mirroring Velocix._prune_response_cache's sweep-then-cap: route_cache sweeps expired entries first (is_valid()/ttl finally does something), then drops oldest by created_at if still over the cap (1024/method). depends.py's caches have no expiry concept (identity-keyed), so they drop oldest by dict insertion order once over 1000.

Added tests/test_cache_eviction.py proving both stay bounded well past their caps. Verified in a fresh venv: 252/252 tests, mypy clean, ruff clean.

Router.route_cache had a CachedRoute.is_valid()/ttl meant to gate cache
freshness, but nothing ever called it, and nothing ever pruned the cache
by size either -- a dynamic route like /users/{id} got one permanent
CachedRoute per distinct id ever requested. depends.py's _sig_cache,
_type_hints_cache, and _plan_cache (keyed by id(func)) had the same shape
of problem: cleanup_caches() existed to trim them but was deleted as dead
code in #9 since nothing called it either.

Both now prune on write, mirroring Velocix._prune_response_cache's
sweep-then-cap: route_cache sweeps expired entries first (finally giving
is_valid()/ttl a job), then drops oldest by created_at if still over
_ROUTE_CACHE_MAX_SIZE (1024, per method). The depends.py caches have no
expiry concept (identity-keyed, not time-keyed), so they just drop the
oldest entries via dict's insertion order once over _CACHE_MAX_SIZE (1000).

Added tests/test_cache_eviction.py: resolves/handlers well past each cap
and asserts the caches stay bounded. Fixes #8.
Copilot AI lite review requested due to automatic review settings September 6, 2026 14:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@magi8101
magi8101 merged commit f8723af into main Sep 6, 2026
2 checks passed
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.

Router.route_cache and depends.py's caches never evict — unbounded memory growth

2 participants