perf(api): batch recommended app catalog lookups (#41218)

This commit is contained in:
向阳
2026-08-25 03:23:52 +00:00
committed by GitHub
parent 12f259ecae
commit d4ed92cb0a
2 changed files with 36 additions and 3 deletions
@@ -10,7 +10,7 @@ from sqlalchemy.orm import Session, sessionmaker
from constants.languages import languages
from extensions.ext_redis import RedisClientWrapper
from models.model import App, RecommendedApp
from models.model import App, RecommendedApp, Site
from services.app_dsl_service import AppDslService
from services.recommended_app_query_service import (
RecommendedAppCatalogPage,
@@ -117,14 +117,23 @@ class DatabaseRecommendedAppCatalogRepository(RecommendedAppCatalogQuery):
*,
session: Session,
) -> tuple[tuple[RecommendedAppRecord, ...], set[str]]:
if not recommended_apps:
return (), set()
app_ids = [recommended_app.app_id for recommended_app in recommended_apps]
apps_by_id = {app.id: app for app in session.scalars(select(App).where(App.id.in_(app_ids))).all()}
sites_by_app_id = {
site.app_id: site for site in session.scalars(select(Site).where(Site.app_id.in_(app_ids))).all()
}
categories: set[str] = set()
records: list[RecommendedAppRecord] = []
for recommended_app in recommended_apps:
app = session.get(App, recommended_app.app_id)
app = apps_by_id.get(recommended_app.app_id)
if app is None or not app.is_public:
continue
site = app.site_with_session(session=session)
site = sites_by_app_id.get(app.id)
if site is None:
continue
@@ -103,6 +103,30 @@ def test_list_recommended_returns_typed_records_and_falls_back_language(
assert record.categories == ("Workflow",)
def test_list_recommended_batches_app_and_site_lookups(
sqlite_engine: Engine,
sqlite_session_factory: sessionmaker[Session],
) -> None:
with sqlite_session_factory() as session:
app_ids = {_add_catalog_app(session).id for _ in range(3)}
select_count = 0
def count_selects(_conn, _cursor, statement: str, _parameters, _context, _executemany) -> None:
nonlocal select_count
if statement.lstrip().upper().startswith("SELECT"):
select_count += 1
event.listen(sqlite_engine, "before_cursor_execute", count_selects)
try:
page = _repository(sqlite_session_factory).list_recommended("en-US")
finally:
event.remove(sqlite_engine, "before_cursor_execute", count_selects)
assert {app.app_id for app in page.recommended_apps} == app_ids
assert select_count == 3
def test_list_recommended_skips_private_apps_and_apps_without_sites(
sqlite_session_factory: sessionmaker[Session],
) -> None: