perf: cache public gallery views

This commit is contained in:
kdletters
2026-05-17 01:19:12 +08:00
parent d9c8473504
commit 81fe3dcf28
39 changed files with 2124 additions and 298 deletions

View File

@@ -243,6 +243,7 @@ npm run check:server-rs-ddd
- Rust 结构体:`BigFishCreationSession`
- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs`
- 索引:`by_big_fish_session_owner_user_id``by_big_fish_session_stage`。公开广场 view 使用 `by_big_fish_session_stage` 读取已发布会话,避免扫整表。
### `big_fish_event`
@@ -254,6 +255,13 @@ npm run check:server-rs-ddd
- Rust 结构体:`BigFishRuntimeRun`
- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs`
### SpacetimeDB view`big_fish_gallery_view`
- Rust view`big_fish_gallery_view`
- 返回类型:`Vec<BigFishWorkSummarySnapshot>`
- 源码:`server-rs/crates/spacetime-module/src/big_fish/session.rs`
- 说明:大鱼吃小鱼公开广场列表投影,只从 `Published` creation session 组装公开卡片字段;`api-server``spacetime-client` 长期订阅 `SELECT * FROM big_fish_gallery_view``SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'` 后,从本地 cache 构造 `/api/runtime/big-fish/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_big_fish_works` procedure个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
### `chapter_progression`
- Rust 结构体:`ChapterProgression`
@@ -340,6 +348,13 @@ npm run check:server-rs-ddd
- Rust 结构体:`Match3DWorkProfileRow`
- 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs`
### SpacetimeDB view`match_3_d_gallery_view`
- Rust view`match3d_gallery_view`
- 返回类型:`Vec<Match3DGalleryViewRow>`
- 源码:`server-rs/crates/spacetime-module/src/match3d/mod.rs`
- 说明:抓大鹅公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server``spacetime-client` 长期订阅 `SELECT * FROM match_3_d_gallery_view``SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'` 后,从本地 cache 构造 `/api/runtime/match3d/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_match3d_works` procedure个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
### `npc_state`
- Rust 结构体:`NpcState`
@@ -479,14 +494,24 @@ npm run check:server-rs-ddd
- `SELECT * FROM puzzle_gallery_view`
- `SELECT * FROM custom_world_gallery_entry`
- `SELECT * FROM match_3_d_gallery_view`
- `SELECT * FROM square_hole_gallery_view`
- `SELECT * FROM visual_novel_gallery_view`
- `SELECT * FROM big_fish_gallery_view`
下列订阅用于统计或配置缓存,订阅失败不会让公开列表连接整体不可用,调用方保留兼容兜底:
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'`
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'`
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'`
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'`
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'`
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'`
- `SELECT * FROM creation_entry_config`
- `SELECT * FROM creation_entry_type_config`
拼图、自定义世界、抓大鹅、方洞挑战、视觉小说和大鱼吃小鱼的公开列表 HTTP 路由都从订阅 cache 读取公开 read model / view。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。
`GET /api/creation-entry/config` 和入口熔断优先从订阅 cache 读取创作入口配置cache 缺失时使用最近一次成功读取的内存快照,再兜底调用 `get_creation_entry_config` procedure 完成空库种子或旧库兼容。
未来可选:若发现页、推荐流和各玩法广场需要统一给浏览器前端直接订阅公开作品列表,只新增 / 统一专用 public read model例如 `public_work_gallery_entry`。该 read model 必须是后端投影后的公开作品卡片契约,覆盖作品类型、公开作品号、标题、摘要、封面、作者展示名、排序键、公开统计和入口开关后的可见性,不暴露玩法领域源表 row shape。前端可选择订阅这个稳定投影来减少 HTTP 拉取,但不能订阅 `puzzle_work_profile``custom_world_profile` 等源表后自行拼装列表BFF 仍保留首屏、SEO / 分享、旧客户端、订阅失败和灰度期间的 HTTP fallback。
@@ -536,6 +561,13 @@ npm run check:server-rs-ddd
- Rust 结构体:`SquareHoleWorkProfileRow`
- 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs`
### SpacetimeDB view`square_hole_gallery_view`
- Rust view`square_hole_gallery_view`
- 返回类型:`Vec<SquareHoleGalleryViewRow>`
- 源码:`server-rs/crates/spacetime-module/src/square_hole/mod.rs`
- 说明:方洞挑战公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server``spacetime-client` 长期订阅 `SELECT * FROM square_hole_gallery_view``SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'` 后,从本地 cache 构造 `/api/runtime/square-hole/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_square_hole_works` procedure个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
### `story_event`
- Rust 结构体:`StoryEvent`
@@ -600,3 +632,10 @@ npm run check:server-rs-ddd
- Rust 结构体:`VisualNovelWorkProfileRow`
- 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs`
### SpacetimeDB view`visual_novel_gallery_view`
- Rust view`visual_novel_gallery_view`
- 返回类型:`Vec<VisualNovelGalleryViewRow>`
- 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs`
- 说明:视觉小说公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;`api-server``spacetime-client` 长期订阅 `SELECT * FROM visual_novel_gallery_view``SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'` 后,从本地 cache 构造 `/api/runtime/visual-novel/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_visual_novel_works` procedure个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。

View File

@@ -157,7 +157,7 @@ Jenkins 按 web / api / Spacetime module / build / deploy / publish 拆分
- `genarrative-api.service` 设置 `LimitNOFILE=65535``TasksMax=2048`;上线后用 `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax``cat /proc/$(pidof api-server)/limits` 核对。
- Nginx `/api/``/admin/api/` 通过 `genarrative_api` upstream 代理到 `127.0.0.1:8082`upstream keepalive 为 64压测时看 `/var/log/nginx/genarrative.access.log` 中的 `request_time``upstream_connect_time``upstream_header_time``upstream_response_time``upstream_status``request_id`
- 作品列表 K6 脚本一次 iteration 默认请求两个公开接口,因此约 50 HTTP req/s 的目标命令使用 `SCENARIO=spike START_RPS=5 PEAK_RPS=25 HOLD=60s END_RPS=5 DETAIL_RATIO=0 npm run loadtest:k6:works`
- 作品列表短期继续由 `api-server` / BFF 订阅 SpacetimeDB 公开 read model 后读本地 cache不让浏览器前端直接订阅完整列表未来如新增 `public_work_gallery_entry` 等专用公开作品列表 read model前端只可订阅稳定投影,不能订阅玩法源表后自行 join、聚合或判断权限
- 作品列表短期继续由 `api-server` / BFF 订阅 SpacetimeDB 公开 read model 后读本地 cache不让浏览器前端直接订阅完整列表未来如新增 `public_work_gallery_entry` 等专用公开作品列表 read model前端只可订阅稳定、低基数、公开的专用投影,禁止订阅 `puzzle_work_profile``custom_world_profile` 等玩法源表后自行 join、聚合或判断权限。前端直订阅落地前必须先补齐权限、字段契约、排序 / 分页、埋点和 BFF 回退策略
- 50 HTTP req/s 验收目标为 `http_req_failed < 1%``p95 < 2s``dropped_iterations = 0`,同时压测窗口内 Nginx 无新增 502。
OpenTelemetry 现阶段可选 OTLP traces / metrics / logs但本地日志与 Nginx 文件日志仍保留: