app.services.apikey_cache_backend module¶
Pluggable cache backends for the API key header lookup.
The in-memory backend preserves the original per-process dict (zero dependency, fast, but one cache per gunicorn worker – revocations only reach the worker that handled the request and other workers serve the cached value until TTL expires). The Redis backend stores entries in a single shared keyspace so every worker observes revocations on the next request.
Selection is driven by configs.APIKEY_CACHE_BACKEND (“memory” or
“redis”) and wired in app/core/container.py.
- class app.services.apikey_cache_backend.ApiKeyCacheBackend(*args, **kwargs)[source]¶
Bases:
ProtocolCache the resolved
(apiKey, active)tuple keyed by sha256 hash.- async get(cache_key)[source]¶
Return the cached value for
cache_key, orNoneif absent.- Parameters:
cache_key (str)
- Return type:
SimpleNamespace | None
- async set(cache_key, value, ttl_seconds)[source]¶
Store
valueundercache_keywith attl_secondslifetime.- Parameters:
cache_key (str)
value (SimpleNamespace)
ttl_seconds (int)
- Return type:
None
- class app.services.apikey_cache_backend.InMemoryApiKeyCacheBackend[source]¶
Bases:
objectPer-process dict cache with monotonic TTL and lazy eviction.
The asyncio lock is lazy-bound on first use and reset by
sync_clearso tests that swap event loops between cases don’t trip “attached to a different loop”. This mirrors the behavior the cache had when it lived onApiKeyServicedirectly.- async get(cache_key)[source]¶
Return the cached value for
cache_key, evicting it if expired.- Parameters:
cache_key (str) – The lookup key (sha256 of the API key plaintext).
- Returns:
Optional[SimpleNamespace] – The cached
(apiKey, active)value, orNoneif absent or past its TTL.- Return type:
SimpleNamespace | None
- async set(cache_key, value, ttl_seconds)[source]¶
Cache
valueundercache_keyforttl_seconds(no-op if ≤ 0).- Parameters:
cache_key (str) – The lookup key.
value (SimpleNamespace) – The
(apiKey, active)value to store.ttl_seconds (int) – Lifetime in seconds; values ≤ 0 are ignored.
- Return type:
None
- class app.services.apikey_cache_backend.RedisApiKeyCacheBackend(client, key_prefix='game:apikey:')[source]¶
Bases:
objectRedis-backed cache shared across workers. Values are stored as compact JSON (
{"apiKey": <prefix>, "active": <bool>}) with TTL set via theEXargument onSETso Redis handles expiration server-side.- Parameters:
key_prefix (str)
- async get(cache_key)[source]¶
Read and deserialize a cached value from Redis.
- Parameters:
cache_key (str) – The lookup key.
- Returns:
Optional[SimpleNamespace] – The decoded
(apiKey, active)value, orNoneif the key is absent.- Return type:
SimpleNamespace | None
- async set(cache_key, value, ttl_seconds)[source]¶
Store
valueas JSON in Redis with a server-side TTL (no-op if ≤ 0).- Parameters:
cache_key (str) – The lookup key.
value (SimpleNamespace) – The
(apiKey, active)value to store.ttl_seconds (int) – Expiry passed to Redis
SET ... EX.
- Return type:
None
- app.services.apikey_cache_backend.build_apikey_cache_backend(backend_name, redis_url, redis_key_prefix)[source]¶
Select the configured backend. Falls back to the in-memory backend with a warning when Redis is requested but
REDIS_URLis missing – so a misconfigured deploy still authenticates (just with the per-process consistency caveat) instead of failing requests outright.- Parameters:
backend_name (str)
redis_url (str | None)
redis_key_prefix (str)
- Return type: