第2章 状态定义与状态转移图设计
本章定义崩溃上报系统的六种核心状态,并设计完整的状态转移图。状态机是重试机制的基础,清晰的状态定义和转移规则能够防止上报死循环、丢失上报、资源泄漏等问题。我们将先以表格形式逐一说明每个状态的含义与生命周期,再给出状态转移图,最后提供状态机骨架代码和关键设计约束。
2.1 六种状态定义
| 状态 | 含义 | 生命周期与备注 |
|---|---|---|
| 初始 | 崩溃记录已写入队列,尚未发起网络上报 | 入口状态,可接收取消信号 |
| 上报中 | 正在向远程服务器发送崩溃数据 | 不可重复触发,超时或网络异常导致转移 |
| 成功 | 服务端返回200 OK,上报数据已被接收 | 终态前置,后续必须进入终止 |
| 失败 | 网络错误、服务端拒绝或业务校验不通过 | 触发重试逻辑,进入重试等待 |
| 重试等待 | 按退避策略等待下一次重试 | 必须设置最大重试次数,超限后进入终止 |
| 终止 | 上报流程结束,释放所有资源 | 终态,不可再转移出去 |
2.2 状态转移图
下图展示了六个状态之间的合法转移路径。箭头方向表示事件触发后的目标状态。关键转移包括:初始→上报中(发起上报)、上报中→成功/失败(上报结果)、失败→重试等待(进入退避)、重试等待→上报中(重试触发)、重试等待→终止(重试次数耗尽或手动取消)、成功→终止(正常结束)。
2.3 转移规则与重试触发条件
状态转移由事件驱动,本系统定义以下关键事件:
- Start:从初始进入上报中,触发崩溃数据打包和网络请求。
- Success:服务端响应 2xx,上报中 → 成功。
- Fail:网络超时、连接断开或服务端返回错误码,上报中 → 失败。
- RetryScheduled:失败后自动发生,失败 → 重试等待,并启动退避定时器。
- RetryFire:退避定时器到期,重试等待 → 上报中。
- Abort:重试次数耗尽、用户手动取消或系统关闭,重试等待 → 终止。
- Complete:成功上报后清理资源,成功 → 终止。
重试等待状态必须与退避算法绑定,常用策略包括固定间隔、指数退避(Exponential Backoff)或加入随机抖动(Jitter)。示例配置:
retry:
max_attempts: 5
base_delay_ms: 1000
multiplier: 2
jitter: true
2.4 状态机代码骨架
以下 C++ 代码展示了状态枚举与基于事件的状态转移核心逻辑。实际工程中应使用锁保护并发访问,并配合回调通知上层。
enum class CrashState {
Initial,
Reporting,
Success,
Failed,
RetryWaiting,
Terminated
};
enum class Event {
Start,
Success,
Fail,
RetryScheduled,
RetryFire,
Abort,
Complete
};
CrashState transition(CrashState current, Event event) {
switch (current) {
case CrashState::Initial:
if (event == Event::Start) return CrashState::Reporting;
break;
case CrashState::Reporting:
if (event == Event::Success) return CrashState::Success;
if (event == Event::Fail) return CrashState::Failed;
break;
case CrashState::Failed:
if (event == Event::RetryScheduled) return CrashState::RetryWaiting;
break;
case CrashState::RetryWaiting:
if (event == Event::RetryFire) return CrashState::Reporting;
if (event == Event::Abort) return CrashState::Terminated;
break;
case CrashState::Success:
if (event == Event::Complete) return CrashState::Terminated;
break;
default:
break;
}
// 非法转移保持原状态,并记录告警
return current;
}
设计约束:禁止从终止状态向外转移,否则会导致资源无法回收。重试等待必须配合
max_attempts 和超时,防止无限重试耗尽电量与带宽。上报中状态应设置全局超时(例如 30 秒),超时后按失败处理。
2.5 状态机边界与模块职责
状态机位于“上报调度器”(Reporter Scheduler)模块内部,对外只暴露以下接口:
void Start():将状态从初始推进至上报中。void OnResponse(bool success):由网络层回调,触发成功/失败转移。void Cancel():用户请求终止,允许从初始或重试等待直接进入终止。
重试定时器不属于状态机内部,而是由调度器持有。状态机只负责“什么事件发生时切换到什么状态”,不负责控制退避延迟时间。
对比:若将退避逻辑嵌入状态机,会导致状态数目膨胀(例如“重试等待-第1次”“重试等待-第2次”)。推荐分离为“状态机+外部退避策略”,使状态图保持简洁,便于测试和持久化。