Objective
Re-introduce a Valkey-backed cache layer for the new BEP-1052
AppConfigFragment repository, replacing the cache-source that was
dropped together with the legacy AppConfig table in #11265 (BA-5822).
The merged-view read path (AppConfigFragmentRepository.app_config(user_id, name))
is the hot path for the WebUI bootstrap (BEP-1052 §6) and currently
hits the DB on every request.
Scope
Mirror the legacy AppConfigCacheSource shape on top of the new
fragment-keyed merged view:
repositories/app_config_fragment/cache_source/cache_source.py:
get_merged_config(user_id, name) — cache lookup keyed by
app_config:merged:{user_id}:{name}
set_merged_config(user_id, name, merged: AppConfigData) — cache
write with TTL; track membership in a domain set for invalidation
invalidate_for_scope(scope_type, scope_id) —
USER: drop the user's per-name keys
DOMAIN / DOMAIN_USER_DEFAULTS: drop every member of the
domain's user set
PUBLIC: drop the whole prefix (or use a small known set)
invalidate_for_policy(config_name) — drop the per-name slice
when an app_config_policies row changes
repositories/app_config_fragment/cache_source/__init__.py re-export
- Wire
AppConfigCacheSource into AppConfigFragmentRepository:
- read path: cache lookup → DB fallback → cache write
- bulk write paths (
bulk_create_my / bulk_update_my /
admin_bulk_*) invalidate after the DB write
AppConfigPolicyRepository writes also invalidate the affected
name slice (forwarded through the fragment cache source)
- Use the shared
suppress_with_log helper so cache failures never
break a request — fall through to DB.
- Unit tests covering hit / miss / invalidate / partial-failure paths.
Out of scope
- New REST / GQL / SDK / CLI endpoints — read path is unchanged from
the user's perspective; this is a transparent acceleration.
- Cache warm-up on startup.
- Cross-host invalidation events (Valkey pub/sub) — relies on the
existing same-process invalidate calls.
Acceptance criteria
References
JIRA Issue: BA-5837
Objective
Re-introduce a Valkey-backed cache layer for the new BEP-1052
AppConfigFragmentrepository, replacing the cache-source that wasdropped together with the legacy AppConfig table in #11265 (BA-5822).
The merged-view read path (
AppConfigFragmentRepository.app_config(user_id, name))is the hot path for the WebUI bootstrap (BEP-1052 §6) and currently
hits the DB on every request.
Scope
Mirror the legacy
AppConfigCacheSourceshape on top of the newfragment-keyed merged view:
repositories/app_config_fragment/cache_source/cache_source.py:get_merged_config(user_id, name)— cache lookup keyed byapp_config:merged:{user_id}:{name}set_merged_config(user_id, name, merged: AppConfigData)— cachewrite with TTL; track membership in a domain set for invalidation
invalidate_for_scope(scope_type, scope_id)—USER: drop the user's per-name keysDOMAIN/DOMAIN_USER_DEFAULTS: drop every member of thedomain's user set
PUBLIC: drop the whole prefix (or use a small known set)invalidate_for_policy(config_name)— drop the per-name slicewhen an
app_config_policiesrow changesrepositories/app_config_fragment/cache_source/__init__.pyre-exportAppConfigCacheSourceintoAppConfigFragmentRepository:bulk_create_my/bulk_update_my/admin_bulk_*) invalidate after the DB writeAppConfigPolicyRepositorywrites also invalidate the affectednameslice (forwarded through the fragment cache source)suppress_with_loghelper so cache failures neverbreak a request — fall through to DB.
Out of scope
the user's perspective; this is a transparent acceleration.
existing same-process invalidate calls.
Acceptance criteria
AppConfigFragmentCacheSourceexists and is wired through therepository with the same read-around-cache pattern the legacy
AppConfigCacheSourceused.domain / name slice before the call returns.
pants check/lint/testclean.References
AppConfigCacheSourceremoved in chore(BA-5822): drop legacy AppConfig layer (preparation for BEP-1052) #11265(
src/ai/backend/manager/repositories/app_config/cache_source/cache_source.pyon
mainhistory).full BEP-1052 surface is in place first.
JIRA Issue: BA-5837