Plannotator PR Context Warm Cache:基于会话级 Promise 缓存消除 PR 概览面板加载闪烁的工程实践
【免费下载链接】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 仓库中的架构决策记录 adr/decisions/002-pr-context-warm-cache-20260630-110601.md下称“ADR-002”剖析其如何通过“会话级 Promise 缓存 后台预热”机制消除 PR Overview 面板打开时的 “Loading PR...” 闪烁。文章首先还原决策背景与设计约束然后给出完整的实现思路与源码级佐证最后讨论失效语义、演进方向与可验证的实验方法。读完本文你将掌握一套可复用的“服务端预热 共享 in-flight Promise 失败驱逐”缓存模式并能直接对照 Plannotator 的 Bun 主服务器与 Pi 扩展服务器两份实现进行落地。一、决策背景PR 概览数据为什么总是“慢半拍”Plannotator 的 PR Overview 面板集中展示 PR 的 description、comments、review threads、checks、labels、merge state 以及 linked issues 等上下文数据。在 ADR-002 记录时2026-06-30其加载流程存在一个明显的时序缺陷审查 UI 打开 Overview 面板后向服务器发起GET /api/pr-context请求服务器此前并未做任何准备工作直到收到该请求才调用fetchPRContext(prRef)去拉取数据于是在 provider 命令如gh pr view、GraphQL 查询等真正跑完之前面板只能显示 “Loading PR...”。换言之面板的等待时间 provider 冷启动的完整耗时而这一等待完全可以通过在服务器端提前预热来消除或缩短。当时的有利条件是主 Bun 审查服务器与 Pi 审查服务器都已经维护了 PR 模式下的会话级缓存PR 列表缓存、PR 切换缓存、栈树缓存具备成熟的会话缓存先例客户端已经统一收敛为“按 PR URL 键控的单一路径”来获取 PR 上下文因此这个问题可以在服务器端修复UI 完全不需要改动。同时ADR-002 明确了两条硬性约束预热的 fetch不得阻塞服务器启动也不得拖慢 PR 切换/api/pr-switch的响应provider 的临时失败不得污染缓存——UI 的重试路径必须能在瞬时故障后重新发起一次全新请求。二、决策内容会话级 PR 上下文 Promise 缓存ADR-002 的决策非常聚焦在两个审查服务器实现中各加入一个按 PR URL 键控、值为PromisePRContext的会话级缓存并配套“启动预热、切换预热、请求时共享、失败驱逐”四条行为规则。2.1 涉及的文件决策点明了两份需要同步修改的服务器实现packages/server/review.ts —— 主 Bun 审查服务器apps/pi-extension/server/serverReview.ts—— Pi 扩展审查服务器。配套的规范文档 adr/specs/pr-context-warm-cache-20260630-110258.md 进一步把修改范围限定为“仅服务器端React 客户端不改一行代码”。2.2 四个核心行为行为一启动预热。PR 审查会话启动时只要初始的prRef与prMetadata已就绪服务器立即在后台调用fetchPRContext(prRef)把返回的 Promise 存入缓存不 await 它。这样 UI 随后发起请求时数据往往已经拉完或正在拉取。行为二请求时共享。/api/pr-context处理器对“当前活跃 PR 的 URL”await 缓存中的 Promise若缓存中已有该 URL 的 Promise无论是否已完成直接共享它等待同一个 Promise若缓存中不存在例如预热失败被驱逐或从未来过则现场创建一个、先存入缓存、再 await 并返回结果。行为三切换预热。当/api/pr-switch切换活跃 PR 后一旦新的prRef已知服务器立刻为新 PR 的 URL 预热上下文缓存。关键点与行为一相同预热不阻塞切换响应切换返回的 diff 载荷仍然即时下发。行为四失败驱逐。若某个 PR URL 的上下文 fetch reject则在把错误返回给调用方之前先从缓存中删除该 URL 的条目。这样后续请求不会被一个陈旧的 rejected Promise 卡死而是能重新发起全新请求完成重试。2.3 API 契约保持不变ADR-002 与规范文档都强调/api/pr-context的响应契约不变——成功时返回原始的PRContextJSON失败时返回{ error: string }状态码 500非 PR 模式返回{ error: Not in PR mode }状态码 400。这一约束保证服务端预热是“无侵入优化”。三、实现要点从设计图到可运行代码规范文档给出了可直接落地的实现骨架理解它能帮你把这个模式迁移到其他系统。3.1 缓存容器与核心 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); // 先存 Promise 再 await天然合并并发 return promise; };这段代码的精妙之处在于以 Promise 为缓存值使“还在飞行中的请求”也能被后续调用方共享避免了重复的 provider 调用.catch中先驱逐再抛出实现“失败不缓存”的语义先set再返回保证并发请求拿到的是同一个 Promise等价于单飞行合并。3.2 启动预热与切换预热两处预热都使用void ... .catch(() {})显式“不等待、不吞错”确保任何异常都不会冒泡到启动或切换主流程// 启动预热初始 prRef 与 prMetadata 已就绪时 if (prRef prMetadata) { void getCachedPRContext(prMetadata.url, prRef).catch(() {}); } // 切换预热新 PR 的 metadata.url 与 prRef 已知后 void getCachedPRContext(pr.metadata.url, prRef).catch(() {});3.3 端点改造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);规范文档还提示了两个运行时差异主服务器可直接从./pr导入PRContext与PRRef类型Pi 服务器则从../generated/pr-types.js导入且 Pi 实现要使用其自身的json(res, ...)辅助函数。这正对应“两个实现必须同步演进”的决策要求。3.4 源码佐证当前的 PRContextLiveCache 正是该决策的落地演进打开当前仓库源码可以看到该决策已演进为共享包 packages/shared/pr-context-live.ts 中的PRContextLiveCache类其设计完整继承了 ADR-002 的四条行为会话级entries new Mapstring, PRContextCacheEntry()对应“按 PR URL 键控的会话缓存”warm(url, ref)方法调用runDetached(...)发起best-effort 后台预热且不等待对应行为一与行为三见 pr-context-live.tsgetContext(url, ref)中“若存在 in-flight 则返回该 Promise否则刷新并共享”对应行为二见 pr-context-live.ts每条 entry 记录error与失败冷却时间failureCooldownMs默认 60s从机制上保证失败可重试而非永久污染。两个服务器端点在当前代码中均已切换到这一统一入口主服务器在 review.ts 通过prContextLive.getContext(prMetadata.url, prRef)处理/api/pr-contextPi 服务器在apps/pi-extension/server/serverReview.ts的对应路由中采用相同调用。fetchPRContext本身则是两个运行时各自的薄封装主服务器见 packages/server/pr.ts内部调用共享的plannotator/shared/pr-provider核心实现Pi 服务器见apps/pi-extension/server/pr.ts。3.5 底层 provider 的失败形态为什么需要驱逐要理解“失败驱逐”为何必要需要看底层 provider 的失败行为。根据研究文档 adr/research/SPIKE-pr-context-warm-cache-20260630-110258.md 的发现GitHub 的 PR context 在gh pr view失败时会 throw对应packages/shared/pr-github.ts的实现这是必须可重试的硬错误GitHub review threads 在 GraphQL 失败时会降级为空列表GitLab 的 context 会并行发起多个只读调用对应packages/shared/pr-gitlab.ts的实现并把部分失败大多降级为空切片。也就是说一部分失败是“软失败”已降级为可用数据一部分是“硬失败”会 reject。缓存策略对硬失败必须做到“驱逐即重试”这正是.catch里先delete再throw的设计动机。四、预期的收益与已知代价ADR-002 在 Consequences 部分对收益与代价做了非常克制的陈述值得逐条还原收益加载闪烁基本消失PR Overview 通常在其数据被 UI 请求时已经就绪消除重复 provider 调用即使预热仍未完成UI 等待的是“已开始的同一份工作”而不是再触发一次重复 fetch失败可重试rejected Promise 会被驱逐出缓存后续请求能重新发起。代价与已知边界会话级缓存可能变陈旧成功获取的 PR context 会在整个审查服务器会话生命周期内被缓存若服务器保持打开期间 comments 或 checks 发生变化数据可能过期。ADR 明确“当前接受这一点”并说明这与既有的 PR list / switch / stack tree 会话缓存风格一致慢 provider 下仍可能显示 loading如果 provider 调用特别慢预热仍可能在 Overview 挂载前未完成此时 UI 仍显示加载但等待的是已在跑的 fetch而非新开一次一次多余的只读调用对“从未打开过 Overview 上下文”的 PR 审查服务器会多执行一次 provider 调用。规范文档认为这是可接受的因为 PR Overview 现在默认打开且该调用是只读的。五、验证方式与演进脉络5.1 验证手段规范文档给出两条验证路径类型检查bun run typecheck根目录 package.json 中定义了bun test与bun run typecheck等脚本可选的手动聚焦检查启动一个 PR 审查 → 立即打开 PR Overview → 确认/api/pr-context正常返回切换到另一个 PR → 确认新 PR 的 Overview 仍能加载且 provider fetch 失败时重试可用。5.2 从 ADR 到实时更新决策的后续演进ADR-002 之后仓库又产生了相邻决策 adr/decisions/003-live-pr-context-updates-20260630-114643.md把“会话级快照缓存”进一步演进为“实时 PR 上下文更新”。这也是当前PRContextLiveCache类如此之大的原因——它在保留 ADR-002 的 warm / in-flight 共享 / 失败冷却语义之上增加了watch订阅、SSE 事件流/api/pr-context/stream端点、周期刷新默认refreshIntervalMs为 30 秒、失败冷却默认 60 秒以及“写操作后立即刷新refreshAfterWrite”等能力。如果你要阅读这段演进建议按此顺序先读 002 决策本文主题 → 读 003 决策 → 再读 pr-context-live.ts 的getContext与warm实现 → 最后对照两个服务器端点。这样你能完整看到“简单的 Promise 缓存”如何成长为“带 TTL、冷却、订阅与 SSE 的实时缓存”。六、可迁移的工程模式总结抛开 Plannotator 的具体业务ADR-002 沉淀的是一套通用且克制的最佳实践可直接迁移到任何“面板类 UI 服务端拉取”的架构中服务端预热而非客户端等待让数据准备发生在“用户可能请求之前”而不是“用户请求之时”缓存 Promise 而非结果缓存值取 Promise天然支持 in-flight 共享多请求自动合并为一次 provider 调用预热必须 detach用void promise.catch(() {})或等价手段发起后台任务绝不阻塞启动与主响应路径失败立即驱逐rejected 的 Promise 绝不留驻缓存保证瞬时故障后重试仍然有效API 契约冻结所有优化都发生在服务端内部对外响应结构一字不改从而把改动风险控制在单侧双实现同步当同一能力存在于两套服务器实现时把共享逻辑下沉到公共包如plannotator/shared/pr-context-live避免两份代码漂移——这正是当前仓库最终的走向。这六条原则合在一起回答了 ADR-002 的核心问题如何在不改 UI、不拖慢启动与切换、不污染缓存的前提下让“PR 概览数据”在用户看到面板之前就已准备就绪。赞分享【免费下载链接】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 PR 上下文预热缓存用会话级 Promise 缓存消除 Overview 加载闪烁Plannotator PR 上下文预热缓存用会话级 Promise 缓存消除 Overview 加载闪烁 导读 本文围绕 Plannotator 仓库中的技Plannotator Live PR Context Updates基于 SSE 的服务端 PR 上下文实时刷新机制解析Plannotator Live PR Context Updates基于 SSE 的服务端 PR 上下文实时刷新机制解析 导读 本文剖析 Plannotat用 MCP Agent 搭建 GitHub PR 自动评审工作流从一次 UI 面板闪烁修复看 AI 代码审查实践用 MCP Agent 搭建 GitHub PR 自动评审工作流从一次 UI 面板闪烁修复看 AI 代码审查实践 本指南以 tarko/mcp agent h人工智能大模型AI Agent桌面应用GUI 自动化浏览器控制MCP 服务MCP Clients上一篇5 分钟搭建网站变更监控用 changedetection.io 盯住降价与补货的完整实操下一篇LevelDB 打开数据库报比较器名称不匹配does not match existing comparator怎么排查创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

PaddleSeg QualityInspector 中的 U-Net:配置文件解析、源码架构与多数据集性能基准

PaddleSeg QualityInspector 中的 U-Net:配置文件解析、源码架构与多数据集性能基准

人工智能计算机视觉预训练 【免费下载链接】PaddleSeg Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting,…

2026/9/25 2:28:08 阅读更多 →
C++ 可移植性指南:类型陷阱、标准库选型与跨平台实践(cppbestpractices)

C++ 可移植性指南:类型陷阱、标准库选型与跨平台实践(cppbestpractices)

文档教程 【免费下载链接】cppbestpractices Collaborative Collection of C Best Practices. This online resource is part of Jason Turners collection of C Best Practices resources. See README.md for more information. 项目地址: https://gitcode.com/gh_…

2026/9/25 2:28:08 阅读更多 →
东三省数学建模A题实战:人口分布与政策多样性量化分析

东三省数学建模A题实战:人口分布与政策多样性量化分析

简介:2026年东三省数学建模A题“中国人口区域分布与发展支持政策的多样性”完整论文与代码资料包,面向数学建模参赛者、指导教师及区域经济研究者。资源围绕人口分布规律、预测建模与政策模拟展开,涵盖熵权法、PCA聚类、Leslie人口预测、GM灰…

2026/9/25 2:28:08 阅读更多 →

最新新闻

RTX 4060 8GB显存跑7B模型:llama.cpp调参实战与FlashAttention优化

RTX 4060 8GB显存跑7B模型:llama.cpp调参实战与FlashAttention优化

1. 为什么偏偏是 RTX 4060 跑 7B 模型这件事值得聊手里有张 RTX 4060,8GB 显存,笔记本端还是桌面端其实差别不小,但核心矛盾是一样的:想跑 7B 级别的模型,显存刚好卡在“能跑但跑不快”的尴尬位置。我前后折腾了差不多…

2026/9/25 3:08:36 阅读更多 →
CentOS 7/8/9 源码编译安装 MySQL 8.0 完整指南

CentOS 7/8/9 源码编译安装 MySQL 8.0 完整指南

聊到在 Linux 上装 MySQL 8.0,很多人第一反应就是yum install mysql-server,或者去官网拖一个二进制包解压完事。但我实际接触过的不少环境,最后还是老老实实走了一遍源码编译安装,倒不是故意跟自己的时间过不去,而是定…

2026/9/25 3:08:36 阅读更多 →
深度揭秘手势识别模块:I2C 0x39寄存器指令与手势识别原理终极解析

深度揭秘手势识别模块:I2C 0x39寄存器指令与手势识别原理终极解析

深度揭秘手势识别模块:I2C 0x39寄存器指令与手势识别原理终极解析 【免费下载链接】gesture-recognition 源师兄扩展项目: 手势识别 | 由源师兄组织创建 项目地址: https://gitcode.com/yuanshixiong/gesture-recognition 本文以大师兄板的 gesture-recognit…

2026/9/25 3:08:36 阅读更多 →
蓝桥杯真题导入QDUOJ:题包制作、批量导入与避坑指南

蓝桥杯真题导入QDUOJ:题包制作、批量导入与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 3:08:36 阅读更多 →
Apache Iceberg JDBC Catalog 集成指南:用关系数据库管理 Iceberg 表元数据

Apache Iceberg JDBC Catalog 集成指南:用关系数据库管理 Iceberg 表元数据

数据湖大数据数据存储 【免费下载链接】iceberg Apache Iceberg 项目地址: https://gitcode.com/gh_mirrors/icebe/iceberg 点击查看 免费下载 JDBC Catalog 是 Apache Iceberg 提供的一种轻量级 Catalog 实现,它把 Iceberg 表的元数据(meta…

2026/9/25 3:08:36 阅读更多 →
OpenChamber 移动端(iOS/Android)Capacitor 壳工程实践指南:从构建管线、原生能力到上架就绪

OpenChamber 移动端(iOS/Android)Capacitor 壳工程实践指南:从构建管线、原生能力到上架就绪

AI Agent人工智能代码智能体交互助手 【免费下载链接】openchamber Agentic Development Environment based on OpenCode AI agent 项目地址: https://gitcode.com/gh_mirrors/op/openchamber 点击查看 免费下载 导读:本文围绕 packages/mobile/HANDOFF…

2026/9/25 3:07:35 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →