核心队列接口设计:QueueTask 抽象、优先级枚举、任务状态生命周期定义

一个轻量级后台队列的可靠性,首先取决于它的任务模型设计。本章定义整个队列框架的三个核心接口构件:任务状态生命周期、优先级枚举以及QueueTask 抽象类。这些接口将成为后续所有调度器、队列存储和容错机制的共同契约。

3.1 任务状态生命周期

每个后台任务从创建到最终结束,会经历以下 5 个状态。状态转换严格单向且不可回退。

状态名称转换条件
INITIAL初始任务刚被创建,尚未入队。
ENQUEUED已入队任务被成功写入队列存储。
RUNNING运行中调度器从队列取出并开始执行。
COMPLETED已完成任务逻辑正常结束。
FAILED失败任务抛出未捕获异常或超时。
设计要点:不允许从 RUNNING 回退到 ENQUEUED,也不支持 COMPLETED 重新激活。如果需要重试,应当创建一个新的任务实例或使用“重试计数”字段在 FAILED 状态下产生副本。

3.2 优先级枚举

为了支持业务分级,队列需要内置优先级机制。枚举值越大优先级越高。

enum class TaskPriority(val level: Int) {
    LOW(0),
    MEDIUM(5),
    HIGH(10)
}

优先级仅在出队阶段生效:调度器每次从队列头部取任务时,总是优先取出 HIGH 级任务,其次 MEDIUM,最后 LOW。同优先级内部按照入队时间 FIFO 排序。

3.3 QueueTask 抽象类

所有业务任务必须继承的基类,它封装了状态管理和唯一标识。

abstract class QueueTask(
    open val id: String = UUID.randomUUID().toString(),
    open val priority: TaskPriority = TaskPriority.MEDIUM
) {
    @Volatile
    var state: TaskState = TaskState.INITIAL
        internal set

    @Volatile
    var createTime: Long = System.currentTimeMillis()
        internal set

    @Volatile
    var retryCount: Int = 0
        internal set

    /** 具体任务逻辑,由子类实现 */
    abstract suspend fun execute()

    /** 任务失败后的回调,默认空实现 */
    open suspend fun onFailure(throwable: Throwable) {}

    /** 任务完成后的回调,默认空实现 */
    open suspend fun onCompleted() {}
}
⚠ 线程安全注意:state、createTime、retryCount 均使用 @Volatile 保证可见性,但复合操作(如状态 + 重试计数同时更新)需要由调度器在外层加锁或使用原子引用。

3.4 接口设计总览

关注点接口/类核心字段/方法
任务标识QueueTask.idUUID 字符串,全局唯一
优先级TaskPriority 枚举LOW(0)、MEDIUM(5)、HIGH(10)
状态管理TaskState 枚举5 个状态,单向流转
业务执行QueueTask.execute()suspend 函数,由调度器在协程中调用
生命周期回调onFailure / onCompleted可选覆盖,用于日志、告警、重试决策

3.5 状态流转与优先级队列示意

下图为任务状态机与优先级队列的关系图,展示了任务从创建到完成/失败的全路径,以及优先级如何影响出队顺序。

QueueTask 状态流转与优先级队列示意 任务状态流转 + 优先级队列结构 优先级枚举 HIGH(10) MEDIUM(5) LOW(0) 出队顺序 HIGH → MEDIUM → LOW 任务状态机 INITIAL ENQUEUED RUNNING COMPLETED FAILED 调度器按优先级 出队后设为 RUNNING
接口一致性约束:所有继承自 QueueTask 的子类必须在 execute() 内部正确处理挂起点(suspend),不得长期阻塞线程。调度器依赖 isActive 或当前协程的取消状态来中断超时任务。

3.6 常见设计错误

  • 状态暴露为 var: 外部可直接修改 task.state,破坏状态机完整性。正确做法是 state 使用 internal set,仅允许同一模块内的调度器写入。
  • 优先级与延迟混用: 优先级控制的是出队顺序,不是执行时刻或延迟时间。如果需要延迟执行,应额外增加 scheduledTime 字段。
  • 忽略序列化兼容: 如果队列需要持久化(如磁盘/数据库),QueueTask 的子类必须支持序列化和反序列化,否则重启后任务丢失。