feat(backend): add LLM registry read cache with pub/sub refresh - #13606
feat(backend): add LLM registry read cache with pub/sub refresh#13606ntindle wants to merge 1 commit into
Conversation
Re-cut of #12359's reviewed core layer onto current dev (part 2 of 9). backend/data/llm_registry/: frozen pydantic models, L1 in-process cache under an asyncio.Lock with Redis-backed L2 (@cached shared_cache), sync read functions (get_model/get_enabled_models/get_schema_options/ get_default_model_slug/get_route/...), and cross-pod refresh fan-out. Changes vs the original branch: - pub/sub rewritten to sharded SPUBLISH/SSUBSCRIBE via the connect_sharded_pubsub_async helper (prod Redis is cluster mode; mirrors event_bus.AsyncRedisEventBus) - ModelMetadata NamedTuple import from backend.blocks.llm replaced with a standalone frozen RegistryModelMetadata (decouples the registry from the enum module it will replace; NamedTuples serialize as JSON arrays) - RegistryModel carries the new schema columns (kind, visibility, minSubscriptionTier, source, catalogRemovedAt, fallbackModelSlug) - get_route(surface, mode, tier) reads LlmModelRoute cells from the same L1 cache for the upcoming copilot routing integration - rest_api lifespan: initial refresh (fail-soft — empty registry degrades to existing hardcoded behavior) + background subscribe task with clean cancellation on shutdown Co-authored-by: Bentlybro <Github@bentlybro.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feat/llm-registry-v2-schema #13606 +/- ##
===============================================================
- Coverage 76.02% 76.01% -0.02%
===============================================================
Files 2688 2688
Lines 204282 204280 -2
Branches 19654 19654
===============================================================
- Hits 155305 155278 -27
- Misses 44639 44662 +23
- Partials 4338 4340 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
After a post-build design review we pivoted from the DB-registry to catalog-as-code: one canonical, schema-validated catalog file is the source of truth (models + costs + copilot routing), updated by PR (catalog-only diffs may ride hotfix→master; the /review bot covers the lane), propagated by CD, with LaunchDarkly demoted to optional cohort experiments and git history as the audit log. Rationale: the admin machinery mostly bought instant-mutation and non-engineer authoring we don't need, and LD is too unreliable to be the load-bearing control layer. Replaced by #13622 — the same read interface and L1 cache, loaded from the catalog file; Redis L2 and pub/sub are unnecessary when the data only changes at deploy. |
Why
Part 2 of 9 of the LLM registry restack (see #13605 for the schema and full context). This layer gives every backend pod a fast, always-warm view of the registry so later parts (public catalog endpoint, copilot routing, admin API) never touch the DB on hot paths.
What
backend/data/llm_registry/— re-cut of @Bentlybro's #12359 core layer:asyncio.Lock; L2 Redis via@cached(ttl=300, shared_cache=True)on the DB fetch. All read functions are sync L1 lookups.get_model,get_all_models,get_enabled_models,get_schema_options,get_default_model_slug,get_all_model_slugs_for_validation, and newget_route(surface, mode, tier)for the routing cells.llm_registry:refreshchannel;refresh_llm_registry+ long-lived subscribe task wired into the rest_api lifespan (fail-soft startup, clean cancellation on shutdown).Still dormant: nothing consumes these reads yet.
How (deltas vs the original branch)
connect_sharded_pubsub_async— prod Redis is cluster mode; classic pub/sub broadcasts to every node. Mirrorsevent_bus.AsyncRedisEventBus.ModelMetadataNamedTuple import fromblocks/llm.pyreplaced with a standalone frozenRegistryModelMetadata— decouples the registry from the module it will eventually replace, and NamedTuples serialize as JSON arrays (wrong for API payloads).RegistryModelcarries the new schema columns (kind,visibility,minSubscriptionTier,source,catalogRemovedAt,fallbackModelSlug).Verification
backend/data/llm_registry/) — record mapping edge cases, refresh/L1 population incl. routes, cache clearing both fetches, sharded pub/sub happy path + handshake filtering + reconnect + close-on-exitpoetry run format+poetry run lintcleanChecklist