ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Plannotator PR 上下文预热缓存:用会话级 Promise 缓存消除 Overview 加载闪烁

Plannotator PR 上下文预热缓存:用会话级 Promise 缓存消除 Overview 加载闪烁 【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载导读本文围绕 Plannotator 仓库中的技术决策文档 synthesis-pr-context-warm-cache-20260630-110258.md 展开讲解如何通过纯服务器端、最小改动的方式为 PR 审查服务器的 Overview 面板预取上下文数据PR 描述、评论、审查线程、CI 检查、标签、合并状态、关联 Issue从而让面板打开时通常能直接命中已就绪的数据而不是等待一次全新的慢速 Provider 调用。读完本文你将掌握detached but owned脱离但拥有的 Promise 缓存设计范式、失败驱逐策略、预热与端点调用的三处接线方式以及它在两个审查服务器实现packages/server/review.ts 与 apps/pi-extension/server/serverReview.ts中的落地形态。问题背景Overview 上下文为什么慢Plannotator 的 PR Overview 面板依赖 PR 上下文数据——包括 PR 描述body、状态state、草稿标记isDraft、标签labels、审查决策reviewDecision、可合并性与合并状态mergeable / mergeStateStatus、评论comments、审查reviews、审查线程reviewThreads、CI 检查checks和关联 IssuelinkedIssues。客户端通过唯一的 hook usePRContext.ts 请求这些数据并在 PR URL 变化时重置状态见 usePRContext.ts 中对prUrl变化的 reset 逻辑Overview 面板挂载时触发该请求见 ReviewPROverviewPanel.tsx。原方案的关键短板在于服务器直到收到/api/pr-context请求才开始执行耗时的 Provider 调用。也就是说客户端面板一打开就要等待一整轮fetchPRContext从零开始于是出现明显的加载闪烁loading flash。而客户端已经具备按 PR URL 重置、单一请求路径的形态因此最简且正确的改动是纯服务器端的——客户端无需任何变更。核心设计决策Decision Pressure预热必须达成两个看似矛盾的目标减少 Overview 加载闪烁同时不拖慢服务器就绪。决策文档给出了三个关键判断detached but owned脱离但拥有启动预热调用不能阻塞服务器启动但又必须能被端点复用。将 Promise 存入 Map 即构成足够的拥有权——端点可以await同一份在途工作而不是另起一个新的 Provider 调用。失败必须驱逐GitHub 场景下gh pr view失败会导致整个上下文抓取失败见 pr-github.ts 中fetchGhPRContext对非零退出码的抛错逻辑。如果失败后的 Promise 仍留在缓存里UI 上的重试按钮会反复拿到同一个失败结果。因此在 Promise 被拒绝时从缓存中删除该条目从而保留现有的重试语义。暂不抽公共抽象两个服务器的实现虽然相似但各自周边的状态是局部且运行时相关的。在各自文件内放一个微型 helper 能让改动范围最小避免引入一个没有更广复用面的新抽象。推荐实现会话级Mapstring, PromisePRContext决策文档给出的核心模式是一个以PR URL 为键、以in-flight 或已完成的fetchPRContextPromise 为值的会话级缓存。注意键的选择与既有prSwitchCache、prStackTreeCache保持一致SPIKE 文档指出主服务器的 PR 列表缓存为 30 秒、另有按 URL 的 switch 缓存与 stack tree 缓存参见 SPIKE-pr-context-warm-cache-20260630-110258.md。缓存与 helperconst prContextCache new Mapstring, PromisePRContext(); const getCachedPRContext (url: string, ref: PRRef): PromisePRContext { const cached prContextCache.get(url); if (cached) return cached; const promise fetchPRContext(ref).catch((error: unknown) { prContextCache.delete(url); throw error; }); prContextCache.set(url, promise); return promise; };这个 helper 完成五件事命中即返回既有 Promise未命中则创建fetchPRContext(ref)立即将 Promise 存入 Map避免并发请求重复发起 Provider 调用Promise 被拒绝时删除 Map 条目保住重试能力返回该 Promise。类型导入的运行时差异两个服务器对PRContext/PRRef的导入路径不同主服务器packages/server/review.ts可以直接从./pr导入Pi 服务器apps/pi-extension/server/serverReview.ts可从../generated/pr-types.js导入生成的类型若从包装模块导入PRRef有摩擦。三处调用点① 启动预热——不 awaitif (prRef prMetadata) { void getCachedPRContext(prMetadata.url, prRef).catch(() {}); }在服务器启动且初始 PR ref 可用时后台即开始抓取但不阻塞就绪。② PR 切换预热——不 awaitvoid getCachedPRContext(pr.metadata.url, prRef).catch(() {});当用户通过/api/pr-switch切换到新 PR、新的prRef确定之后立即对新 PR 的 URL 发起预热且不得延迟 switch 的响应。主服务器的 switch 路径在 review.ts 处更新prMetadata/prRef后立即预热Pi 服务器对应 serverReview.ts。③ 端点 await——复用同一份工作if (!isPRMode || !prRef || !prMetadata) { return Response.json({ error: Not in PR mode }, { status: 400 }); } const context await getCachedPRContext(prMetadata.url, prRef); return Response.json(context);/api/pr-context处理器await缓存的 Promise若预热尚未完成它等待的是同一个在途 Promise而不是再发一次 Provider 调用。Pi 实现中应使用 Pi 服务器的json(res, ...)helper。API 契约保持不变这是本次改动的一条硬约束——端点的对外行为完全不变spec-pr-context-warm-cache-20260630-110258.md 明确定义场景返回成功既有PRContextJSONProvider 失败{ error: string }状态码 500非 PR 模式{ error: Not in PR mode }状态码 400客户端 hook 依赖成功时的原始PRContextJSON 与失败时的{ error }结构usePRContext.ts因此契约稳定意味着客户端零改动。仓库现状从本地 Map 模式到共享的PRContextLiveCache值得说明的是当前仓库中的实际落地形态在决策文档所描绘的本地 Map 模式基础上进一步演进共享模块 packages/shared/pr-context-live.ts 中提供了createPRContextLiveCache内部以 URL 为键维护entriesMap见 pr-context-live.ts并实现了决策文档的核心语义warm(url, ref)发起 best-effort 后台刷新不等待pr-context-live.tsgetContext(url, ref)返回最新上下文并共享任何在途刷新pr-context-live.tsrefresh()合并 in-flight 请求、广播 loading/updated/error 事件并维护inflightPromisepr-context-live.ts。两个服务器均以同一方式接线createPRContextLiveCache({ fetchContext: fetchPRContext })创建实例再用一个warmPRContexthelper 包装warm主服务器 review.tsPi 服务器 serverReview.ts启动预热与切换预热分别落在 review.ts / review.ts 和 serverReview.ts / serverReview.ts/api/pr-context处理器则await prContextLive.getContext(prMetadata.url, prRef)review.ts、serverReview.ts。此外该共享缓存还支持watch()供/api/pr-context/stream实时推送与refreshAfterWrite()Provider 写入后立即刷新。这一实现有对应的单元测试佐证pr-context-live.test.ts 中的用例shares one in-flight refresh across warmup, GET, and watchers验证了预热、GET、watcher 三者共享同一个在途刷新Provider 只被调用一次——这正是决策文档中端点等待同一份工作语义的测试固化。fetchPRContext本身是运行时包装器主服务器在 pr.tsPi 服务器在 apps/pi-extension/server/pr.ts最终委托给共享的 Provider 实现。各 Provider 的失败特性也影响缓存语义GitHub 在gh pr view失败时整体抛错pr-github.ts而 GraphQL 抓取审查线程失败时降级为空列表GitLab 侧则从源码结构看采用并行只读调用组装上下文并将部分失败降级为空切片pr-gitlab.ts 起的fetchGlMRContext。验证方式按规格文档改动后用根脚本验证类型bun run typecheckbun test与bun run typecheck定义于 package.json 附近的根脚本。可选的聚焦手动检查清单启动一次 PR 审查立即打开 PR Overview确认/api/pr-context正常返回且命中预热缓存不再从零抓取切换到另一个 PR确认新 PR 的 Overview 仍能加载且当 Provider 抓取失败时重试仍然有效因为失败条目已被驱逐。风险与边界会话内可能过期若 PR 评论或 CI 检查在审查服务器打开期间发生变化会话级缓存的上下文可能变旧。这与请求的行为一致也符合既有的会话缓存风格PR 列表、switch、stack tree 缓存都是会话级的。慢调用下仍可能显示 loading对特别慢的 Provider 调用预热可能赶在 Overview 挂载之前仍未完成。此时 UI 仍会显示 loading但等待的是已在运行的那次抓取而不会额外启动第二次。一次多余的只读调用对于从未打开 Overview 上下文的 PR 审查服务器会多做一次 Provider 调用。由于 PR Overview 现在默认打开且该调用是只读的这个代价可以接受。明确不做的事What Not To Change不改客户端 hook 与 Overview 面板唯一请求路径与按 URL 重置逻辑保持不变不改/api/pr-context响应结构契约稳定是零客户端改动的前提不做跨服务器会话的持久化缓存生命周期限于当前会话不引入 TTL除非用户认为新鲜度比会话一致性更重要不在同一改动中重构 stack-tree 缓存保持改动范围聚焦于 PR 上下文预热。延伸阅读决策综述synthesis-pr-context-warm-cache-20260630-110258.md规格文档specs/pr-context-warm-cache-20260630-110258.md技术调研SPIKE-pr-context-warm-cache-20260630-110258.md共享缓存实现与测试packages/shared/pr-context-live.ts、packages/shared/pr-context-live.test.ts客户端消费端packages/review-editor/hooks/usePRContext.ts、packages/review-editor/dock/panels/ReviewPROverviewPanel.tsx赞分享【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载相关推荐Husky.Net 常见问题解决方案Husky.Net 常见问题解决方案 项目基础介绍 Husky.Net 是一个用于简化 Git 钩子管理的开源项目主要面向 .NET 开发者。它允许开发者在提Nativefier构建缓存预热CI预加载缓存Nativefier构建缓存预热CI预加载缓存 在Nativefier的开发过程中构建速度和效率是开发者关注的重要问题。特别是在持续集成CI环境中频繁CLI桌面应用开发工具termux-packages构建缓存策略缓存预热与预加载termux packages构建缓存策略缓存预热与预加载 概述 Termux packages作为Android平台上最流行的Linux环境包管理系统其构开发工具包管理器构建工具上一篇OpenChamber 拖拽排序实践指南基于 dnd-kit 实现桌面与移动端一致的可排序交互下一篇免费开源风扇控制神器FanControl终极配置指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表