refactor(cache): build the key only where the backend is used; report media_type - #276
Merged
Merged
Conversation
… media_type @cache built the cache key before the no-store and backend-bypass branches, where it only fed debug logs, so a custom key_builder ran for nothing on those routes. Build it right before the backend read, log the path in the bypass branches, test the request with 'is None' instead of Request.__len__, and move the Cache-Control closure to a module-level _build_cache_control. /cached-records now reports each entry's stored media_type; content_type stays "bytes" for compatibility. CACHE_KEY_MAX_PARTS is renamed to CACHE_KEY_MAX_SPLIT, since it is a maxsplit count, with the old name kept as an alias. Closes #182 Closes #184
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #182
Closes #184
Both are part of #121.
#182:
@cachewrapperprivate, nottl,ttl=0) never touch the backend, so they used the key only in debug logs, and a customkey_builderran for nothing there. Those logs now show the request path.if not req(which relies onRequest.__len__) becomesif req is None.build_cache_controlclosure is now a module-level_build_cache_control(...)with keyword-only arguments and the same output. It is still built once per decorated route.No behaviour change apart from when
key_builderis called. It still runs exactly once per GET that reads the backend: miss, hit and 304 alike.#184: monitoring routes
/cached-recordsgains amedia_typefield with the storedCacheEntry.media_type, ornullwhen there is none.content_typestays and is always"bytes"for compatibility.CACHE_KEY_MAX_PARTSis amaxsplitcount, so it is renamedCACHE_KEY_MAX_SPLIT. The old name remains as an alias.media_typeand points readers away fromcontent_type.Tests
tests/test_cache_internals.py:key_builderis not called forno_store,private, nottl,ttl=0(including a revalidating request) or non-GET;_build_cache_controlcovers the directive order,stale-if-errorandno-cachedropping the rest.tests/test_routes.py:media_typefor JSON andtext/plainentries,nullfor an entry without one, and the constant alias.no_storefails only the new key-builder tests;media_type=Nonefails only the new media-type test;must-revalidateunderno-cachefails the new_build_cache_controlcase plus the existingtest_no_cache_with_revalidate.uv run pytestpassed without live servers: 813 passed and 190 skipped, where the skips are the Redis/Memcached tests. Coverage is 93.03%, withcache.pyandroutes.pyat 100%.CHANGELOG
Added
/cached-recordsreports each entry'smedia_type. It is the media type the response was stored with, ornullwhen it had none.content_typeis still returned for compatibility but is always"bytes".CACHE_KEY_MAX_PARTSinfastapi_cachex.routesis renamedCACHE_KEY_MAX_SPLIT, since it is amaxsplitcount; the old name remains as an alias. (#184)Changed
@cachebuilds the cache key only when it reads or writes the backend. A customkey_builderis no longer called forno_store,privateor TTL-less routes, where the key only fed debug logs. (#182)