在做 #3774 (视图 override 读写命名空间)时,顺路核对了 ObjectStackAdapter 的元数据缓存键,发现的相邻观察。不在该单范围内 ,按 PD #10 单独立此单,未在 PR #3777 里动。
这是 observation-class :今天没有用户会撞到它(症状只是「少了一层缓存」,不是错数据),故只打 finding,不进 pm:queue,交由分诊定级。
事实
packages/data-objectstack/src/index.ts 里 views:{objectName} 这个缓存键被 invalidate 了 4 次 :
2775: this.metadataCache.invalidate?.(`views:${objectName}`); // updateViewConfig
2936: this.metadataCache.invalidate?.(`views:${objectName}`);
2969: this.metadataCache.invalidate?.(`views:${objectName}`);
2986: this.metadataCache.invalidate?.(`views:${objectName}`);
但没有任何路径写入过它 。全文件仅 6 处 metadataCache.get(...),其 cacheKey 分别是:
行
cacheKey
2444
objectName(getObjectSchema)
2685
view-overrides:{objectName}
2722
view:{objectName}:{viewId}
3006
app:{appId}
3027
page:{pageId}
3389
{category}:{name}
没有 views: 前缀的那个。listViews() 自己是直接 fetch、完全不过缓存 的(await this.client.meta.getItems('view'),外面没有 metadataCache.get 包裹)。
(行号取自 PR #3777 合入后的树;在 origin/main 上是同样的结构,只是行号偏移。)
推论
那 4 行 invalidate 是惰性代码 :失效一个永不存在的条目,恒为 no-op。
真正的效果是 listViews() 每次调用都打一次 GET /api/v1/meta/view 。ObjectView 一次页面加载里,视图切换器(listViews)与 override 批量读(listViewOverrides,有缓存)会各打一次同一个 /meta/view 路由 —— 同一份数据取两遍。
为什么现在只当观察记录
请求数没有回归:#3774 之前 listViewOverrides 打的是 /meta/{对象名},也是一次请求,只不过取回来是空的。修复只改了第二次请求的 URL,没有新增往返 。所以这是一条既有的效率观察,不是 #3774 引入的。
两条可能方向(留给分诊,未擅自选)
删掉那 4 行 invalidate (enforce-or-remove 的「remove」侧):承认 listViews 就是不缓存,别留一个看起来在维护、实则空转的失效调用。
给 listViews 补上缓存 (enforce 侧),让那 4 行真正生效;更进一步可让 listViews 与 listViewOverrides 共享同一份 type='view' 枚举结果(两者本来就读同一批行,data-objectstack 的 listViewOverrides 读的是 meta/{对象名}(把对象名当 metadata type),写却落在 type='view' —— 两边键空间不相交,已保存的视图个性化永远读不回来 #3774 后连「属于哪个对象」的判断都已收敛到同一个 viewItemObjectName() accessor 了),一次页面加载省掉一次往返。
方向 2 更符合两个方法本已同源的现状,但它改的是缓存语义(草稿预览 previewDrafts 分支不能与已发布列表共用键),需要分诊确认后再动 —— 所以这里只记录,不实现。
相关
Generated by Claude Code
在做 #3774(视图 override 读写命名空间)时,顺路核对了
ObjectStackAdapter的元数据缓存键,发现的相邻观察。不在该单范围内,按 PD #10 单独立此单,未在 PR #3777 里动。这是 observation-class:今天没有用户会撞到它(症状只是「少了一层缓存」,不是错数据),故只打
finding,不进pm:queue,交由分诊定级。事实
packages/data-objectstack/src/index.ts里views:{objectName}这个缓存键被 invalidate 了 4 次:但没有任何路径写入过它。全文件仅 6 处
metadataCache.get(...),其 cacheKey 分别是:objectName(getObjectSchema)view-overrides:{objectName}view:{objectName}:{viewId}app:{appId}page:{pageId}{category}:{name}没有
views:前缀的那个。listViews()自己是直接 fetch、完全不过缓存的(await this.client.meta.getItems('view'),外面没有metadataCache.get包裹)。(行号取自 PR #3777 合入后的树;在
origin/main上是同样的结构,只是行号偏移。)推论
invalidate是惰性代码:失效一个永不存在的条目,恒为 no-op。listViews()每次调用都打一次GET /api/v1/meta/view。ObjectView 一次页面加载里,视图切换器(listViews)与 override 批量读(listViewOverrides,有缓存)会各打一次同一个/meta/view路由 —— 同一份数据取两遍。为什么现在只当观察记录
请求数没有回归:#3774 之前
listViewOverrides打的是/meta/{对象名},也是一次请求,只不过取回来是空的。修复只改了第二次请求的 URL,没有新增往返。所以这是一条既有的效率观察,不是 #3774 引入的。两条可能方向(留给分诊,未擅自选)
listViews就是不缓存,别留一个看起来在维护、实则空转的失效调用。listViews补上缓存(enforce 侧),让那 4 行真正生效;更进一步可让listViews与listViewOverrides共享同一份type='view'枚举结果(两者本来就读同一批行,data-objectstack 的 listViewOverrides 读的是meta/{对象名}(把对象名当 metadata type),写却落在type='view'—— 两边键空间不相交,已保存的视图个性化永远读不回来 #3774 后连「属于哪个对象」的判断都已收敛到同一个viewItemObjectName()accessor 了),一次页面加载省掉一次往返。方向 2 更符合两个方法本已同源的现状,但它改的是缓存语义(草稿预览
previewDrafts分支不能与已发布列表共用键),需要分诊确认后再动 —— 所以这里只记录,不实现。相关
meta/{对象名}(把对象名当 metadata type),写却落在type='view'—— 两边键空间不相交,已保存的视图个性化永远读不回来 #3774 / PR fix(data-objectstack): read view overrides from the type='view' namespace they are written to (#3774) #3777(override 读写命名空间;本观察是在其测量过程中发现的)Generated by Claude Code