> ## Documentation Index
> Fetch the complete documentation index at: https://www.worldmonitor.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 可靠性、健康与新鲜度

> World Monitor 的错误追踪、熔断器、优雅降级、系统健康指示器、数据新鲜度等级与服务状态监控，说明仪表盘如何向用户明确展示数据缺口、过期来源与降级状态，而不是默默显示陈旧数据，面向评估平台的工程师与希望参与贡献的开发者阅读。

本页属于[设计哲学](https://www.worldmonitor.app/docs/zh/architecture.md)指南，该页索引全部主题。部署拓扑、目录结构与 CI/CD 请参阅 [`ARCHITECTURE.md`](https://github.com/koala73/worldmonitor/blob/main/ARCHITECTURE.md)。

***

## 错误追踪

### Sentry 错误噪声过滤

Sentry SDK 初始化包含 `beforeSend` 钩子和 `ignoreErrors` 列表，抑制已知的不可操作错误来源 — 完全发生在无 source-map 帧的压缩代码中的 Three.js WebGL 遍历崩溃、来自浏览器扩展的跨域 Web Worker 构建失败、iOS 媒体元素崩溃，以及扩展注入的 jQuery `$`。Three.js 过滤器特别避免一刀切抑制：仅丢弃*所有*栈帧都是匿名或来自压缩 bundle 的事件。如果哪怕有一帧具有 source-map 的 `.ts` 文件名，该事件将被保留以供调查。

### 错误追踪与生产强化

Sentry 在生产环境中捕获未处理异常和 Promise 拒绝，具备环境感知路由（生产环境在 `worldmonitor.app`，预览环境在 `*.vercel.app`，localhost 和 Tauri 桌面端禁用）。

配置包含 30+ 个 `ignoreErrors` 模式，抑制以下噪声：

* **第三方 WebView 注入** — Twitter、Facebook 和 Instagram 内嵌浏览器注入引用未定义变量（`CONFIG`、`currentInset`）的脚本
* **浏览器扩展** — 失败 `importScripts` 或违反 CSP 策略的 Chrome/Firefox 扩展
* **WebGL 上下文丢失** — MapLibre/deck.gl 中可自恢复的瞬时 GPU 崩溃
* **iOS Safari 怪癖** — 后台标签页被杀导致的 IndexedDB 连接断开、自动播放策略导致的 `NotAllowedError`
* **网络瞬时问题** — `TypeError: Failed to fetch`、`TypeError: Load failed`、`TypeError: cancelled`
* **MapLibre 内部崩溃** — 源自地图分块的 style layers、light 和 placement 中的空访问

自定义 `beforeSend` 钩子提供第二阶段过滤：抑制单字符错误消息（压缩产物）、来自浏览器扩展的 `Importing a module script failed` 错误（通过栈跟踪中的 `chrome-extension:` 或 `moz-extension:` 识别），以及栈跟踪源自地图分块文件时的 MapLibre 内部空访问崩溃。

**分块重载守卫** — 部署后，持有过期浏览器标签页的用户在动态导入的分块具有新内容哈希文件名时可能遇到 `vite:preloadError` 事件。守卫监听此事件，每个构建最多重载一次页面，并将已用掉的重载记录在 `sessionStorage` 中（`sessionStorage` 不可用时改用 `localStorage`）。应用成功启动后不会清除该记录，因此每次加载都失败的分块（例如被广告拦截器屏蔽的分块）只会造成一次重载，而不是循环重载。没有任何存储能保存该记录时，守卫完全不重载。延迟加载的 Sentry 加载器通过 `preventDefault()` 认领其自身分块的失败，因此被屏蔽的 Sentry 分块永远不会触发页面重载。跨越后续部署仍保持打开的标签页由过期构建检查处理。

**存储配额管理** — 当设备的 localStorage 或 IndexedDB 配额耗尽时（移动版 Safari 5MB 限制常见），全局 `_storageQuotaExceeded` 标志禁用持久缓存（IndexedDB + localStorage 回退）和工具 `saveToStorage()` 函数的所有后续写入尝试。该标志在首次 `name === 'QuotaExceededError'` 或 `code === 22` 的 `DOMException` 时设置，防止重复失败写入导致的级联错误。读取操作继续正常 — 缓存数据仍可访问，仅新写入被抑制。

事务以 10% 采样以在可观测性与成本间平衡。发布追踪（`worldmonitor@{version}`）支持跨部署的回归检测。

***

## 容错

外部 API 不可靠。速率限制、中断和网络错误不可避免。系统实现**熔断器**模式以维持可用性。

### 熔断器模式

每个外部服务都包装在追踪失败的熔断器中：

```
Normal → Failure #1 → Failure #2 → OPEN (cooldown)
                                       ↓
                               5 minutes pass
                                       ↓
                                    CLOSED
```

**冷却期间行为：**

* 新请求返回缓存数据（如可用）
* UI 显示"暂时不可用"状态
* 不进行 API 调用（防止轰炸）

### 受保护服务

| 服务 | 冷却 | 缓存 TTL |
| - | - | - |
| Yahoo Finance | 5 分钟 | 10 分钟 |
| Polymarket | 5 分钟 | 10 分钟 |
| USGS 地震 | 5 分钟 | 10 分钟 |
| NWS 天气 | 5 分钟 | 10 分钟 |
| FRED 经济 | 5 分钟 | 10 分钟 |
| Cloudflare Radar | 5 分钟 | 10 分钟 |
| ACLED | 5 分钟 | 10 分钟 |
| GDELT | 5 分钟 | 10 分钟 |
| FAA 状态 | 5 分钟 | 5 分钟 |
| RSS 订阅源 | 每源 5 分钟 | 10 分钟 |

RSS 订阅源使用每源独立熔断器 — 一个失败订阅源不影响其他。

### 优雅降级

当服务进入冷却时：

1. 缓存数据继续显示（过期但可用）
2. 状态面板显示服务健康度
3. 冷却到期时自动恢复
4. 无需用户干预

***

## 系统健康监控

状态面板（通过标题栏健康指示器访问）提供数据源状态和系统健康度的实时可见性。

### 健康指示器

标题栏显示系统健康徽章：

| 状态 | 视觉 | 含义 |
| - | - | - |
| **健康** | 绿点 | 所有数据源正常运行 |
| **降级** | 黄点 | 部分来源处于冷却 |
| **不健康** | 红点 | 多个来源失败 |

点击指示器展开完整状态面板。

### 数据源状态

状态面板列出所有数据订阅源及其当前状态：

| 状态 | 图标 | 描述 |
| - | - | - |
| **活跃** | ● 绿 | 正常抓取数据 |
| **冷却** | ● 黄 | 暂时暂停（熔断器） |
| **已禁用** | ○ 灰 | 图层未启用 |
| **错误** | ● 红 | 持续失败 |

### 每订阅源信息

每条订阅源显示：

* **来源名称** - 数据提供商
* **上次更新** - 距上次成功抓取的时间
* **下次刷新** - 距下次计划抓取的倒计时
* **冷却剩余** - 距熔断器重置的时间（如处于冷却）

### 为何重要

外部 API 不可靠。状态面板帮助你了解：

* **数据新鲜度** - 新闻订阅源是最新的还是过期的？
* **覆盖缺口** - 哪些来源当前不可用？
* **恢复时间线** - 失败来源何时重试？

这种透明性使你能知情解读仪表盘数据。

***

## 数据新鲜度追踪

除简单的"在线/离线"状态外，系统为每个数据源追踪细粒度新鲜度，以指示数据可靠性和陈旧度。

### 新鲜度等级

| 状态 | 颜色 | 标准 | 含义 |
| - | - | - | - |
| **新鲜** | 绿 | 在预期间隔内更新 | 数据为最新 |
| **老化** | 黄 | 过去 1-2× 预期间隔 | 数据可能略过期 |
| **过期** | 橙 | 过去 2-4× 预期间隔 | 数据已过时 |
| **关键** | 红 | 过去 >4× 预期间隔 | 数据不可靠 |
| **已禁用** | 灰 | 图层已关闭 | 不抓取 |

### 来源专属阈值

每个数据源有校准的新鲜度预期：

| 来源 | 预期间隔 | "新鲜"阈值 |
| - | - | - |
| 新闻订阅源 | 5 分钟 | \<10 分钟 |
| 股票报价 | 1 分钟 | \<5 分钟 |
| 地震 | 5 分钟 | \<15 分钟 |
| 天气 | 10 分钟 | \<30 分钟 |
| 航班延误 | 10 分钟 | \<20 分钟 |
| AIS 船舶 | 实时 | \<1 分钟 |

### 视觉指示器

状态面板为每个来源显示新鲜度：

* **彩色点** 指示新鲜度等级
* **距更新时间** 显示确切陈旧度
* **下次刷新倒计时** 显示数据何时更新

### 为何重要

理解数据新鲜度对决策至关重要：

* "新鲜"的地震订阅源意味着显示了近期事件
* "过期"的新闻订阅源意味着你可能错过突发报道
* "关键"的 AIS 流意味着船舶位置不可靠

这种可见性使你在解读仪表盘时能适当校准置信度。

### 核心 vs. 可选来源

数据源按其对风险评估的重要性分类：

| 分类 | 来源 | 影响 |
| - | - | - |
| **核心** | GDELT、RSS 订阅源 | 风险评分所需 |
| **可选** | ACLED、军事、AIS、天气、经济 | 增强但非必需 |

战略风险概览面板根据核心来源可用性调整其显示：

| 状态 | 显示模式 | 行为 |
| - | - | - |
| **充足** | 完整数据视图 | 所有指标带置信度显示 |
| **有限** | 有限数据视图 | 显示"数据有限"警告横幅 |
| **不足** | 不足数据视图 | "数据不足"消息，无风险评分 |

### 新鲜度感知风险评估

复合风险评分根据数据新鲜度调整：

```
If core sources fresh:
  → Full confidence in risk score
  → "All data sources active" indicator

If core sources stale:
  → Display warning: "Limited Data - [active sources]"
  → Score shown but flagged as potentially unreliable

If core sources unavailable:
  → "Insufficient data for risk assessment"
  → No score displayed
```

这防止了系统实际缺乏数据做出判断时发出虚假"全部安全"信号。

***

## 服务状态监控

服务状态面板追踪 WorldMonitor 用户可能依赖的外部服务的运行健康度。

### 受监控服务

| 服务 | 状态端点 | 解析器 |
| - | - | - |
| Anthropic (Claude) | status.claude.com | Statuspage.io |
| OpenAI | status.openai.com | Statuspage.io |
| Vercel | vercel-status.com | Statuspage.io |
| Cloudflare | cloudflarestatus.com | Statuspage.io |
| AWS | health.aws.amazon.com | 自定义 |
| GitHub | githubstatus.com | Statuspage.io |

### 状态等级

| 状态 | 颜色 | 含义 |
| - | - | - |
| **正常运行** | 绿 | 所有系统功能正常 |
| **降级** | 黄 | 部分中断或性能问题 |
| **部分中断** | 橙 | 部分组件不可用 |
| **重大中断** | 红 | 重大服务中断 |

### 为何重要

外部服务中断可能影响：

* AI 摘要（OpenRouter 中断）
* 部署管道（Vercel、GitHub 中断）
* API 可用性（Cloudflare、AWS 中断）

监控这些服务在仪表盘功能异常时提供上下文。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.