0
Fork 0
mirror of https://github.com/Silent1566/webhtv.git synced 2026-11-14 02:00:15 +00:00
webhtv-mys/docs/interface-failover-design.md
Silent1566 484bdc9dd9 docs: 记录接口容灾默认自动模式复审
Verification: Focused tests InterfaceFailoverPolicyTest/StateTest/OrderStoreTest/BackupPreferenceFilterTest passed; Mobile and Leanback Arm64 javac passed; git diff --check passed

Task-Guard: failover-default-auto-review-20260914
2026-09-14 15:21:00 +08:00

11 KiB

接口容灾设计

1. 目标

为点播接口增加统一的容灾机制。当用户当前使用的接口无法正常拉取数据或加载失败时,系统按用户配置的接口顺序切换到下一个可用接口。

本设计只覆盖“点播接口配置加载失败”场景,不覆盖以下场景:

  • 站点首页、详情、搜索失败
  • 站点播放地址解析失败
  • 播放器内核切换、解码切换
  • 直播接口、壁纸接口
  • 换源容灾

2. 三种模式

模式 默认 行为
关闭 是 当前接口失败后仅提示错误,不自动切换
自动容灾 否 当前接口失败后按顺序自动尝试下一个未尝试接口
手动确认 否 当前接口失败后弹出确认框,由用户决定是否切换到下一个或指定接口

三种模式互斥,同一时刻只生效一种。

2.1 关闭

行为完全保持现状:

  1. 用户配置或手动选择某个点播接口。
  2. 加载失败。
  3. 弹出错误提示。
  4. 不切换接口,不发起额外请求。

关闭模式是安全回退锚点。实现后如果发现任何自动切换副作用,应优先回退到关闭模式。

2.2 自动容灾

  1. 用户配置或手动选择某个点播接口。
  2. 加载失败。
  3. 系统从用户排序后的接口序列中,找到当前接口之后的下一个未尝试接口。
  4. 自动加载该接口。
  5. 加载成功则走正常成功链路。
  6. 全部候选接口都已失败后,弹出最终错误提示。

自动容灾不需要用户参与。每次切换应显示当前尝试的接口名或地址,避免用户误以为仍在加载原接口。

2.3 手动确认

  1. 用户配置或手动选择某个点播接口。
  2. 加载失败。
  3. 弹出确认框,列出剩余未尝试接口。
  4. 用户可选:
    • 切换到下一个接口
    • 指定切换到某个接口
    • 取消切换
  5. 用户确认后才发起下一次加载。
  6. 用户取消后不再继续本轮容灾。

手动确认模式只在加载失败后弹出一次确认框。若用户选择切换后再次失败,可以继续弹出下一次确认框,或维持单次确认后结束本轮;推荐后者,避免连续弹窗打扰。

3. 接口序列与排序

3.1 排序来源

接口容灾顺序来自用户手动排序的接口序列。若用户没有自定义顺序,则按当前数据库默认顺序。

当前默认顺序:

SELECT * FROM Config WHERE type = 0 ORDER BY time DESC

新增手动排序后,不修改数据库结构,不引入数据库 migration。排序持久化到应用偏好存储,键按点播接口类型作用域隔离。

3.2 存储键

建议新增:

interface_order_vod

值格式:

[
  "https://example.com/config-a.json",
  "https://example.com/config-b.json",
  "https://example.com/config-c.json"
]

按接口 URL 唯一标识。重复 URL 只保留一次。

3.3 排序规则

  1. 取当前点播接口集合。
  2. 按用户排序键重排。
  3. 用户排序中不存在的接口追加到末尾。
  4. 已删除接口的排序键保留在偏好存储中但不参与排序。
  5. 新增接口默认追加到末尾。

3.4 排序入口

建议在现有接口历史弹层中增加排序入口:

  • 手动拖拽调整顺序
  • 排序后立即保存
  • 当前接口也参与排序
  • 当前接口保持可见,不因“当前使用中”而剔除

这样可以保证用户看到完整容灾顺序,而不是只见“其他接口”的局部顺序。

4. 失败判定

仅以下情况触发接口容灾:

  1. 配置 URL 请求失败。
  2. HTTP 状态异常。
  3. JSON 解析失败。
  4. 配置返回 msg 字段。
  5. 配置解析出的 sites 为空。
  6. 配置仓库 urls 解析结果为空。

以下情况不触发接口容灾:

  1. 接口加载成功,但首页无内容。
  2. 接口加载成功,但详情或搜索失败。
  3. 接口加载成功,但播放地址解析失败。
  4. 接口加载成功,但播放器内核或解码失败。
  5. 用户主动取消加载。
  6. 更高优先级的加载请求已使当前请求失效。

4.1 不做播放链路容灾

接口加载成功后,首页、详情、搜索、播放链路失败应继续由现有站点健康排序、播放器内核容灾、换源机制处理。接口容灾不应接管这些场景,否则会把“配置不可用”与“站点不可用”混淆,带来更大副作用。

5. 自动容灾流程

5.1 状态

本轮容灾只维护一次状态:

failoverRoundId
originUrl
attemptedUrls
candidateUrls
currentIndex

5.2 步骤

  1. 记录本轮 failoverRoundId。
  2. 构造候选接口序列:InterfaceOrderStore.sortConfigs(Config.getAll(0))。
  3. 将当前接口 URL 加入 attemptedUrls。
  4. 从 currentIndex 开始向后查找第一个未尝试接口。
  5. 加载该接口。
  6. 若失败,重复步骤 4。
  7. 若成功,走正常成功链路。
  8. 若没有更多未尝试接口,走最终失败链路。

5.3 防重复

  1. 同一轮内按 URL 去重。
  2. 已失败接口不再重试。
  3. 新一轮容灾必须重置状态。
  4. 用户手动选择接口应开启新一轮,而不是沿用上一轮状态。
  5. 同一轮内避免环形死循环。

5.4 尝试上限

为防呆,建议同轮最多尝试:

min(candidateCount, 3)

如果用户明确需要更多候选,可以后续再调大。第一版保守上限有助于控制请求和提示成本。

6. 手动确认流程

6.1 弹框内容

  1. 标题:接口加载失败
  2. 副标题:当前接口名称或地址
  3. 剩余候选接口列表
  4. 操作:
    • 切换到下一个
    • 指定接口
    • 取消

如果剩余候选接口只有一个,可将“指定接口”简化为“切换到该接口”。

6.2 交互

  1. 失败后弹出一次。
  2. 用户选择“切换到下一个”后,加载下一个候选接口。
  3. 若再次失败,结束本轮,不再继续弹窗。
  4. 用户选择“指定接口”时,先展示剩余候选接口列表,再由用户选择一个。
  5. 用户选择“取消”后,结束本轮。

6.3 状态

手动确认与自动容灾共享同一个候选序列构造逻辑,但增加一个用户决策等待点。若用户取消或未决策,不继续发起请求。

7. 提示

7.1 自动容灾提示

  1. 切换时显示“正在尝试下一个接口”。
  2. 尽量带出接口名称或地址。
  3. 多次连续切换时避免频繁刷新同一个 Toast。
  4. 全部失败后显示最终错误。

7.2 手动确认提示

  1. 失败后立即弹出确认框。
  2. 确认框需要能看到当前失败接口和剩余候选接口。
  3. 用户取消后显示“已取消接口切换”。

7.3 关闭模式提示

  1. 只显示当前加载失败的原始错误。
  2. 不显示“已尝试 N 个接口”。
  3. 不显示任何切换提示。

8. 成功与失败链路

8.1 成功

  1. 接口加载成功。
  2. 更新当前接口。
  3. 触发现有配置成功事件。
  4. 触发现有首页、站点、解析器、规则等消费方刷新。
  5. 若来自容灾,通知可带出“已切换到 xxx”。

8.2 失败

  1. 所有候选接口都已失败。
  2. 只回调一次最终错误。
  3. 不发中间配置事件。
  4. 不触发首页、详情、播放器中间刷新。
  5. 保持当前失败前的界面状态。

8.3 中间失败不发事件

自动容灾过程中,每次中间失败都不应触发 ConfigEvent.vod()。只有最终成功或最终失败后才发一次事件,避免首页或播放页反复刷新。

9. 实现位置

9.1 建议集中点

  1. VodConfig
  2. BaseConfig

理由:

  1. 接口加载集中在这两层。
  2. 成功/失败回调集中。
  3. UI 只需要在最终回调中处理提示。
  4. 不需要每个入口各自实现 fallback。

9.2 不建议的位置

  1. VodFragment
  2. HomeActivity
  3. SettingFragment
  4. 各 UI 回调

这些位置只能处理最终提示,不应承载容灾状态机。否则手机端、TV 端、远程接口、配置仓库等入口会出现重复实现和行为不一致。

10. 设置存储

10.1 设置键

建议新增:

interface_failover_mode

值:

0 = 关闭
1 = 自动容灾
2 = 手动确认

10.2 默认值

默认值应为 1,即自动容灾。

10.3 设置入口

建议放在增强设置页,归类为“接口容灾”或“接口韧性”。

10.4 备份与同步

设置键和接口排序键应纳入备份与一键同步,保证用户换机后容灾顺序和模式不丢失。

11. 回退路径

11.1 运行时回退

  1. 用户把模式切回“关闭”。
  2. 立即停止当前容灾轮次。
  3. 不发起新的候选接口请求。

11.2 实现回退

如果上线后发现严重副作用,应优先回退到关闭模式默认值,而不是直接移除排序或设置项。

11.3 代码回退

如果必须回退代码,应保留排序存储结构和设置键,避免用户数据丢失。

12. 验证

12.1 单元测试

建议至少覆盖:

  1. 接口排序保存、恢复、去重。
  2. 新增接口追加到末尾。
  3. 已删除接口不参与排序。
  4. 关闭模式不触发容灾。
  5. 自动容灾失败后尝试下一个未尝试接口。
  6. 自动容灾全部失败后只回调一次最终错误。
  7. 自动容灾同轮内不重复尝试同一接口。
  8. 自动容灾同轮内尝试次数不超过上限。
  9. 手动确认用户取消后不继续请求。
  10. 手动确认用户切换后只尝试一次。
  11. 中间失败不发 ConfigEvent.vod()。
  12. 成功后走正常成功链路。
  13. 设置键纳入备份。
  14. 排序键纳入备份。

12.2 手动验证

  1. 设置页切换三种模式。
  2. 关闭模式:接口失败后仅提示,无切换。
  3. 自动容灾:接口失败后自动切换到下一个接口。
  4. 自动容灾:所有接口失败后显示最终错误。
  5. 手动确认:接口失败后弹出确认框。
  6. 手动确认:用户取消后不切换。
  7. 手动确认:用户确认后切换到指定或下一个接口。
  8. 接口排序调整后,容灾顺序随之变化。
  9. 容灾成功后首页、站点、解析器、规则正常刷新。
  10. 容灾过程中不出现首页或播放页重复刷新。

12.3 回归边界

以下能力不应受本设计影响:

  1. 站点健康排序
  2. 换源
  3. 播放器内核自动切换
  4. 解码自动切换
  5. 直播接口
  6. 壁纸接口
  7. 配置仓库导入

13. 边界与不做事项

  1. 不合并所有接口的全局配置。
  2. 不把多个接口的 sites/parses/rules/headers/proxy/webHomeExtensions 合并成一个虚拟配置。
  3. 不对站点首页、详情、搜索、播放失败做接口级切换。
  4. 不修改 Config 数据库实体。
  5. 不引入数据库 migration。
  6. 不将接口容灾与“聚合全部接口”混为同一开关。
  7. 默认开启自动容灾;用户可随时切换为关闭或手动确认。
  8. 不在关闭模式下发起额外请求。
  9. 不在中间失败后触发全局事件。