排查实战:从后端健康到 UI 状态机的系统化根因分析)
【免费下载链接】hermes-workspaceNative web workspace for Hermes Agent — chat, terminal, memory, skills, inspector.项目地址https://gitcode.com/gh_mirrors/he/hermes-workspace点击查看免费下载本文以 Hermes Workspace 仓库中的迭代交接文档memory/goals/2026-05-03-playground-training-grounds/iterations/008-3002-loading-loop-handoff.md为骨架系统梳理一次典型的后端全部健康、前端却持续转圈的加载循环排查过程。文章将带你还原完整的排障链路环境变量与双端口对比、健康探针验证、Shell 兜底补丁的实现原理以及针对 UI 状态机、路由漂移、生成路由树与浏览器残留状态的五大候选假设与验证步骤适合所有遇到服务明明正常但页面死循环 loading问题的前端开发者直接复用。一、问题背景一次发生在双开发服务器之间的加载循环本次排障发生在 HermesWorld 功能合并进本地main分支并推送到 GitHub 之后。交接文档记录了如下关键现场仓库路径交接文档功能分支feat/agent-view-port-from-controlsuite合并方式先将本地main合入功能分支解决冲突、构建通过再把功能分支合回本地main最后推送main到远端推送区间8f31e113b..cb2ecec5f产品状态HermesWorld 已合入main并上线3005的 preview/worktree 行为正常但3002本地 main 工作区 dev server出现了持续加载循环即使反复合并、刷新也无法恢复。值得注意的合并冲突解决策略被明确记录dashboard / agent-view / chat 布局一律以main为准而 HermesWorld 品牌与多人环境配置在冲突处予以保留。本次冲突涉及四个文件.env.examplesrc/components/agent-view/agent-view-panel.tsxsrc/screens/chat/chat-screen.tsxsrc/screens/dashboard/dashboard-screen.tsx这一策略本身即为排障提供了第一条线索如果加载循环来自布局层面那么以 main 为准的冲突裁决可能把某个只在功能分支上正确的状态带歪了。二、已完成的排查动作把传输与认证层先全部排除交接文档详细记录了在将问题移交前已经做过的六类验证动作这些动作构成了一个标准的自底向上排查模板。1. 发现双端口后端不一致首个真实线索3002与3005两个 dev server 起初分别对接了不同的后端3002→ portable backend端口86453005→ enhanced backend端口8642。这种错配在对比 HermesWorld 行为时具有误导性两个前端看到的网关能力完全不同任何功能差异都可能被错误归因。文档明确将其判定为likely wrong for comparing HermesWorld behavior。2. 修改本地 main 的.env通过编辑/Users/aurora/hermes-workspace/.env把两处后端地址从8645统一切到8642HERMES_API_URLhttp://127.0.0.1:8645 → http://127.0.0.1:8642 CLAUDE_API_URLhttp://127.0.0.1:8645 → http://127.0.0.1:8642从仓库源码看这两个环境变量在前端请求链中扮演核心角色src/server/gateway-capabilities.ts以及src/routes/api/*下大量路由如gateway-status.ts、auth-check.ts、connection-status.ts、models.ts、claude-proxy/$.ts都从该模块解析CLAUDE_API、BEARER_TOKEN等网关地址前端会话、模型列表、技能、任务等能力全部依赖这一基础配置。vite.config.ts中同样存在对HERMES_API_URL的处理前端侧请求经 Vite 代理转发到该地址。3. 反复重启与 Vite 缓存清理3002在以下操作后均被多次重启切换后端 URL删除node_modules/.viteVite 预构建缓存目录以清除失效的依赖预构建产物干净的pnpm dev重新启动。4. 验证健康探针端点重启后3002报告的观测结果全部健康GET /api/connection-status → {ok:true,mode:enhanced,backend:http://127.0.0.1:8642} GET /api/auth-check → {authenticated:true,authRequired:false} GET /api/gateway-status → 合法 JSON3002 与 3005 均正常对照源码可以确认这些端点的实际语义。以 connection-status.ts 为例它聚合了网关探测结果ensureGatewayProbed()、config.yaml中的活动模型并计算出status、chatReady、modelConfigured、chatMode、capabilities等字段chatMode取值enhanced-claude/portable/disconnected。而auth-check.ts路由则直接基于ensureGatewayProbed的探测结果判定是否需要认证。也就是说auth 端点健康意味着网关探测链路本身是通的。5. 一条值得警惕的假线索排查中曾发现/api/gateway-capabilities返回了应用 HTML 而非 JSON一度非常可疑。但随后确认当前main上真实路由是/api/gateway-status且该端点健康因此判定为假线索。这提示了一个排障要点先确认你要打的端点在当前分支上是否真的存在文件系统路由TanStack File Router中过期的历史路由名容易制造噪音。6. 加入 Shell 兜底补丁为应对启动遮罩卡死场景在src/components/workspace-shell.tsx中加入了兜底检查。该补丁目前仍在仓库中可从源码直接验证其实现workspace-shell.tsx// 导入 fetchClaudeAuthStatus useEffect(() { if (typeof window undefined || connectionVerified) return let cancelled false const verify async () { try { const status await fetchClaudeAuthStatus(3000) // ① /api/auth-check3s 超时 if (cancelled) return setAuthStatus(status) setConnectionVerified(true) return } catch { // ② 失败则降级到 /api/connection-status } try { const res await fetch(/api/connection-status, { cache: no-store }) if (!res.ok || cancelled) return const data await res.json() if (data?.ok || (data?.chatReady data?.modelConfigured)) { setAuthStatus({ authenticated: true, authRequired: false }) setConnectionVerified(true) } } catch { // 两个探针都失败时保持启动屏 } } void verify() return () { cancelled true } }, [connectionVerified])补丁的意图非常明确代码注释原文即使ConnectionStartupScreen自身卡住只要/api/auth-check或/api/connection-status健康Shell 仍应解锁。注意补丁后3002也被重启过但循环依旧。兜底补丁背后启动状态机的真实结构结合workspace-shell.tsx与connection-startup-screen.tsx的源码可以完整还原启动状态机的控制流Shell 维护authStatus与connectionVerified两个状态并派生出authState { checked: !isClient || connectionVerified, authenticated, authRequired }workspace-shell.tsx渲染时只要!authState.checked就挂载全屏ConnectionStartupScreenworkspace-shell.tsx否则正常渲染子路由若authRequired !authenticated则先渲染LoginScreenworkspace-shell.tsxConnectionStartupScreen内部有一个2 秒轮询 5 秒失败面板 4 秒静默自动启动的状态机connection-startup-screen.tsxconst POLL_INTERVAL_MS 2_000 // 失败后每 2s 重试一次 tryConnect const FAILURE_REVEAL_MS 5_000 // 5s 未连上则展示失败/设置面板 const AUTO_START_DELAY_MS 4_000 // 4s 后静默 POST /api/start-claude 尝试拉起网关其连接循环逻辑为调用fetchClaudeAuthStatus()内部请求/api/auth-check默认 5 秒超时见 claude-auth.ts成功则回调onConnected(status)令 Shell 解锁失败则setTimeout(tryConnect, POLL_INTERVAL_MS)继续轮询。只要/api/auth-check反复返回异常而非快速成功这个 2 秒轮询在外观上就是一个永不停歇的 loading loop——这正与文档健康端点 循环仍在的现象高度吻合。启动屏还提供了Auto-Start Hermes Agent Gateway按钮POST /api/start-claude、服务器日志展示以及按平台macOS/Windows/Linux区分的四步手动配置指南HERMES_API_URL指向任意 OpenAI 兼容后端 → 安装 hermes-agent →hermes setup→hermes gateway run其中网关即监听:8642。三、遗留谜团与五条强假设完成上述排查后结论是后端、认证、网关全部健康 Shell 兜底补丁已生效却仍然循环。据此文档给出了五种候选解释并给每条假设配套了可执行的验证动作——这部分是本文最具复用价值的排障清单。假设 A根本不是启动/认证遮罩ConnectionStartupScreen可能压根没有出现在屏幕上用户看到的可能是 splash、路由 shell、playground 过渡加载页或其他 loader。验证动作立刻向使用者要一张截图精确识别屏幕上的组件必要时在疑似组件中临时加入极其醒目的调试文本以区分是哪一个。假设 Bmain 与 worktree 的路由/布局漂移对照3002main与3005可用的 worktree preview之间的文件差异src/components/workspace-shell.tsxsrc/components/connection-startup-screen.tsxsrc/routes/__root.tsxsrc/routes/playground.tsxsrc/screens/playground/playground-screen.tsxsrc/screens/chat/components/chat-sidebar.tsx这正是合并冲突以 main 为准策略下最可能出现隐性漂移的区域——布局 shell 的某一处小差异如isChromeFreeSurface、isOnPlaygroundRoute等条件分支就可能让 3002 停在某个中间态。假设 C生成的路由树 / Vite dev 状态异常开发日志反复出现两类告警send-stream-live-tools.ts does not export a Route routeTree.gen.ts was modified by another process during processing前者无害后者则暗示routeTree.gen.tsTanStack Router 自动生成的路由注册文件在多个进程间互相改写可能让3002内存中持有损坏的路由状态。验证动作检查3002是否在服务一份错误的内存态必要时删除生成的routeTree.gen.ts与node_modules/.vite后冷启动。假设 D浏览器侧残留状态包括localStorage/sessionStorage、持久化的 Zustand 状态、Service Worker 缓存、过期路由状态等。验证动作检查 onboarding 完成标志、持久化的 auth/loading 标志并尝试无痕窗口 清缓存复现。假设 EHermesWorld 过渡加载器自身在循环playground-screen.tsx中存在transitioning状态与TransitionLoadingScreen组件源码可见playground-screen.tsx它是一个z-[95]的全屏过渡层用金色entering — 世界名标题、无限循环的hermes-loading-bar动画与随机 Hermes 语录构成active为真时透明度为 1。验证动作搜索transitioning、TransitionLoadingScreen与 playground 路由进入逻辑检查active是否因某个状态未复位而永远为true——若如此这便是一个完全独立于后端健康状态的纯 UI 级循环。文档给出的总体结论也印证了这一点问题已不再是简单的后端/认证故障更可能是一个具体的 UI 组件/状态机或 3002 相对 3005 存在的路由/布局/状态分歧。四、可复用的排障命令与观测基线交接文档沉淀了一组可直接复用的探针命令适用于任何端口# 3002 健康三连 curl -s http://localhost:3002/api/connection-status curl -s http://localhost:3002/api/auth-check curl -s http://localhost:3002/api/gateway-status # 3005 对比 curl -s http://localhost:3005/api/connection-status curl -s http://localhost:3005/api/gateway-status排障接近尾声时3002达到的健康基线观测项期望值modeenhancedbackendhttp://127.0.0.1:8642auth-checkauthenticated: truegateway-status合法 JSON开发日志位于/tmp/hermes3002.log可配合tail -f实时观察需要重点过滤的两类噪音见上文假设 C。五、给后续接手者的六步行动清单先要截图确定循环属于启动/auth 遮罩、splash、路由 shell、playground 过渡加载页还是其他 loader对比 3002 与 3005 的路由/布局状态重点看workspace-shell.tsx、__root.tsx与启动/auth 流程确认兜底补丁真的编译进了 3002检查构建产物或运行时行为审计客户端状态假设localStorage/sessionStorage键、onboarding 完成标志、持久化的 auth/loading 标志检查 HermesWorld 过渡加载器自身是否在循环搜索transitioning与TransitionLoadingScreen及 playground 路由进入逻辑必要时为疑似遮罩组件临时加上超醒目的调试文本让使用者直接报出屏幕上到底是哪一个组件。六、经验沉淀这类问题的通用诊断顺序回顾整场排障可以提炼出适用于任何服务健康但前端死循环场景的诊断顺序先证伪传输层统一前后端环境变量HERMES_API_URL/CLAUDE_API_URL确保对比实验的两个 dev server 指向同一个后端再证伪探针层用 curl 逐个验证健康端点并确认端点在该分支上真实存在警惕过期路由名制造的假线索再证伪遮罩层为启动组件加入 shell 级兜底验证如本仓库workspace-shell.tsx中的降级探测同时核对启动屏内部的轮询/超时常量是否与探针行为匹配最后攻坚 UI 层聚焦状态机transitioning一类布尔状态是否永久卡真、路由生成产物routeTree.gen.ts多进程改写、以及浏览器持久化状态。当所有探针都绿、页面仍在转圈时问题的边界几乎必然落在 UI 状态机或开发态的路由/布局分歧上——这正是本次交接文档最终给出的结论也是排查同类问题时应最先怀疑的领域。仓库中的完整交接记录008-3002-loading-loop-handoff.md可作为后续继续排查的起点相关的启动组件、认证工具与网关能力源码connection-startup-screen.tsx、claude-auth.ts、gateway-capabilities.ts可随时按需深入。赞分享【免费下载链接】hermes-workspaceNative web workspace for Hermes Agent — chat, terminal, memory, skills, inspector.项目地址https://gitcode.com/gh_mirrors/he/hermes-workspace点击查看免费下载相关推荐Hermes Workspace 开发服务器加载死循环排障实录多实例 Vite 争抢 TanStack Router 生成文件根因分析Hermes Workspace 开发服务器加载死循环排障实录多实例 Vite 争抢 TanStack Router 生成文件根因分析 导读 这是一份基于 H猫抓cat-catch资源嗅探实战指南3种安装方式拿取页面视频与m3u8流媒体猫抓cat catch资源嗅探实战指南3种安装方式拿取页面视频与m3u8流媒体 猫抓cat catch是一款免费开源的 浏览器媒体资源嗅探扩展 它能音视频ingress-nginx健康检查后端服务状态监控ingress nginx健康检查后端服务状态监控 在现代微服务架构中确保服务的高可用性是至关重要的。ingress nginx作为Kubernetes集群后端API网关负载均衡云原生上一篇x402 EVM 支付机制深度解析Go SDK 中 exact / upto 方案的架构、接入与扩展指南下一篇让 Calibre 中文书名不再变拼音NoTrans 插件 3 步上手完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考