4. 超时恢复策略基础:任务状态机模型

异步迁移任务的核心挑战在于:网络抖动、资源争抢、服务重启等异常会导致任务长时间无响应。要设计可靠的超时恢复与重试机制,首先需要为每个任务建立有限状态机(FSM),并实现状态持久化。状态机定义了任务的生命周期,持久化则确保状态在进程崩溃后不丢失。

4.1 四态模型定义

我们将每个异步迁移任务抽象为以下四种基本状态,所有状态转换必须满足严格的前置条件:

状态 枚举值 含义 可转换至
Pending 0 任务已创建,等待调度执行 Running
Running 1 任务正在执行中,可能包含多个子步骤 Failed, Completed
Failed 2 任务因超时、异常或业务错误终止 Pending(重试)
Completed 3 任务正常执行完毕,数据已迁移成功 (终态)
设计要点:Failed 状态允许回退到 Pending,这是重试策略的基础。Completed 为终态,不允许任何后续转换,防止数据重复迁移。

4.2 状态转换图

下图展示了任务从创建到结束的完整状态流转路径,以及超时/异常触发的回退机制:

异步迁移任务状态机模型 Pending 等待调度 Running 执行中 Completed 终态 Failed 异常/超时 重试回退 Failed → Pending 调度 成功 超时/异常 业务失败 重试

4.3 状态持久化方案

状态持久化是状态机可靠运行的基石。我们采用数据库 + 缓存的双层架构,兼顾一致性与性能:

  • 持久层(MySQL/PostgreSQL): 记录任务完整状态、重试次数、最后更新时间、错误信息。作为权威数据源。
  • 缓存层(Redis): 存储任务当前状态和超时时间戳(TTL),用于快速判断任务是否超时,减少数据库压力。
核心表结构(task_state):
CREATE TABLE task_state (
    task_id        VARCHAR(64)   PRIMARY KEY,
    status         TINYINT       NOT NULL COMMENT '0:Pending 1:Running 2:Failed 3:Completed',
    retry_count    INT           DEFAULT 0,
    max_retries    INT           DEFAULT 3,
    timeout_sec    INT           DEFAULT 300,
    started_at     DATETIME(3),
    updated_at     DATETIME(3)   DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
    error_msg      TEXT,
    INDEX idx_status_updated (status, updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.4 状态转换原子操作

状态转换必须保证原子性,防止并发场景下出现状态不一致。推荐使用乐观锁或CAS(Compare and Swap)方式更新:

-- 将 Running 状态的任务标记为 Failed(仅当当前状态仍为 Running 时)
UPDATE task_state
SET status = 2, error_msg = 'timeout', updated_at = NOW(3)
WHERE task_id = 'xxx' AND status = 1;
避坑指南:不要使用“先查询再更新”的两步操作,这会导致竞态条件。始终使用带条件更新的单条 SQL 或 Redis Lua 脚本保证原子性。

4.5 超时检测与状态回退流程

超时恢复的核心逻辑是一个后台巡检线程(或定时任务),周期性扫描超时任务并触发状态回退:

  1. 扫描超时任务: 查询所有 status = 1 (Running) 且 updated_at < NOW() - timeout_sec 的记录。
  2. 尝试状态转换: 对每个超时任务执行 UPDATE ... WHERE status = 1 AND task_id = ?,确保只有当前仍为 Running 的任务被转换。
  3. 判断重试上限: 若 retry_count < max_retries,将状态置为 Pending 并递增 retry_count;否则置为 Failed 并记录最终错误。
  4. 发送告警: 当任务连续重试失败达到上限时,触发运维告警。
超时检测与状态回退流程 扫描超时 Running 任务 CAS 更新状态 检查重试次数 置为 Pending,retry_count++ 重试次数未超限 置为 Failed,触发告警 重试次数已达上限 retry_count < max_retries retry_count ≥ max_retries

4.6 状态机与重试策略的协同

状态机模型为重试策略提供了清晰的边界条件。在实际开发中,需要将以下参数纳入配置管理:

  • timeout_sec: 单次执行超时阈值,根据迁移数据量动态调整。
  • max_retries: 最大重试次数,建议默认 3 次,防止无限重试导致资源耗尽。
  • retry_interval: 重试间隔,可采用指数退避(如 10s、30s、90s)。
生产建议:在 Failed 状态中记录详细的 error_msg 和堆栈信息,便于排查根因。同时,为每个状态转换添加审计日志,方便追踪任务生命周期。