topfans/docs/superpowers/specs/2026-04-08-task-management-system-design.md
zheng020 ceb0159290 docs: update task management design based on review
修正内容:
- InitUserTasks 粒度:改为创建 onboarding_status + 每日任务进度
- ReportTaskEvent:从内部 RPC 改为移动端 API POST /api/tasks/report-event
- InitUserTasksRequest 增加 star_id 字段
- 每日任务流程:补充用户注册 → InitUserTasks 步骤
- 展示收益流程:补充 failed 记录对用户不可见的说明
- 展示收益响应:补充 star_id 字段
- activity-admin 收益记录页面:支持查看 failed 记录和手动补发

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 20:49:53 +08:00

28 KiB
Raw Permalink Blame History

任务管理系统设计文档

创建日期: 2026-04-08 项目: TopFans 任务管理系统 服务: activity-admin (Python FastAPI) + taskService (Go Dubbo-go) + 共享 PostgreSQL


一、整体架构

┌─────────────────────────────────────────────────────────────────┐
│                         移动端                                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐   │
│  │  每日任务页面  │  │  引导任务页面 │  │  展示收益/奖励领取   │   │
│  └──────┬───────┘  └──────┬───────┘  └──────────┬───────────┘   │
└─────────┼─────────────────┼─────────────────────┼───────────────┘
          │                 │                     │
          │  Triple/HTTP   │                     │
          ▼                 ▼                     ▼
┌─────────────────────────────────────────────────────────────────┐
│                     taskService (新服务,端口 20005)              │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Mobile API Handler (HTTP/Triple)             │   │
│  │  /api/tasks/daily/*  /api/tasks/guide/*  /api/tasks/*   │   │
│  └──────────────────────────────────────────────────────────┘   │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐  │
│  │ DailyTaskService│  │OnboardingService│  │ RevenueService   │  │
│  └────────┬────────┘  └────────┬────────┘  └────────┬────────┘  │
│           │                     │                     │           │
│  ┌────────▼─────────────────────▼─────────────────────▼────────┐  │
│  │                    Repository Layer (GORM)                 │  │
│  └───────────────────────────────────────────────────────────┘  │
│                         │                                       │
│           ┌─────────────▼─────────────┐                        │
│           │   DailyResetWorker        │                        │
│           │   + RevenueAutoClaimWorker │                        │
│           │   (PostgreSQL Advisory    │                        │
│           │    Lock05:00 Asia/Shanghai)│                       │
│           └───────────────────────────┘                        │
└─────────────────────────────────────────────────────────────────┘
          │                    ▲                    ▲
          │  Triple RPC       │                    │
          ▼                    │                    │
┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
│  galleryService │   │  userService    │   │  activity-admin │
│  (OnExhibition  │   │  (UpdateCrystal │   │  (任务定义管理) │
│   Completed RPC)│   │   Balance +     │   │  直接操作DB    │
│                 │   │   AddExperience)│   │                 │
└─────────────────┘   └─────────────────┘   └─────────────────┘
          │                    ▲                    ▲
          └────────────────────▼────────────────────┘
                         PostgreSQL

二、设计决策汇总

2.1 服务职责划分

服务 职责
activity-admin (Python) 任务定义管理、进度查询、统计、手动重置
taskService (Go) 移动端 API、内部 RPC、奖励发放、定时任务
PostgreSQL 共用数据库

2.2 核心设计决策

决策项 选择
移动端 API 提供方 新建独立 taskService 微服务
引导完成上报 前端每步完成立即调用 /api/tasks/guide/complete
每日任务重置 PostgreSQL Advisory Lock每天 05:00 Asia/Shanghai 执行
引导阶段推进 前端主动调用 /api/tasks/onboarding/advance-stage
每日任务奖励 手动领取(单个或一键领取)
引导任务奖励 阶段切换时统一发放
展示收益发放 统一到次日 05:00 自动发放,支持手动领取
展示收益计算 由调用方galleryService计算后传入
每日任务 scope 每个 (user_id, star_id) 各自独立
InitUserTasks 创建 user_onboarding_status + 该 star_id 下的每日任务进度;新增粉丝身份时创建对应进度
重置日志 记录到 task_reset_log 表
旧字段处理 is_first_login_bonus_claimed、has_friend_display_bonus 标记废弃
奖励发放失败 记录日志 + 本地重试 N 次(可配置),仍失败标记 failed
重置时区判断 按自然天,每天 05:00 执行一次
重置范围 全局所有用户所有 star_id
引导上报 key 动态配置,数据库存什么 key前端就上报什么 key
阶段切换检查 后端检查当前阶段所有任务是否已完成,未完成拒绝切换
引导任务 不允许重复完成,不重置
claimed 状态 每日重置时也重置回 pending
收益自动发放 分批发放,每条记录结果保存,失败重试 N 次(可配置)
统计页面 多指标完成率、领取率等、多维度star_id、时间范围
Worker 设计 共用一个 Worker05:00 先重置再发收益
日志监控 接入现有日志和监控体系
健康检查 不实现,复用 Dubbo-go 框架自带能力
错误码 复用现有 BaseResponse.code 体系
分页规范 page + page_size + total
引导状态返回 POST /api/tasks/guide/complete 返回当前引导完整状态
锁 key 设计 pg_advisory_lock(YYYYMMDD)
taskService 端口 20005
taskService 调用 userService 直接调用UpdateCrystalBalance + AddExperience
activity-admin 直接操作数据库,不通过 taskService API

三、数据库设计

3.1 ER 图

┌─────────────────────────┐     ┌─────────────────────────────┐
│   task_definitions       │     │  onboarding_stage_config     │
├─────────────────────────┤     ├─────────────────────────────┤
│ id (PK)                 │     │ id (PK)                     │
│ star_id                 │     │ stage                       │
│ task_key                │────▶│ required_task_keys (TEXT[]) │
│ task_type               │     │ crystal_reward              │
│ name                    │     │ exp_reward                  │
│ description             │     │ ...                         │
│ crystal_reward          │     └─────────────────────────────┘
│ exp_reward             │               ▲
│ ...                    │               │
└─────────────────────────┘               │
        │                                 │
        │ 1:N                     1:N    │
        ▼                                 │
┌─────────────────────────┐     ┌─────────────────────────────┐
│ user_daily_task_progress│     │  user_onboarding_progress   │
├─────────────────────────┤     ├─────────────────────────────┤
│ id (PK)                 │     │ id (PK)                    │
│ user_id                 │     │ user_id                    │
│ star_id                 │     │ task_key ───────────────────┘
│ task_key                │◀────│
│ status                  │     │  ┌─────────────────────────┐
│ completed_at            │     │  │user_onboarding_status   │
│ claimed_at             │     │  ├─────────────────────────┤
│ ...                    │     │  │ user_id (PK)            │
└─────────────────────────┘     │  │ current_stage           │
                                │  │ status                  │
                                │  │ is_first_login_bonus_   │
                                │  │   claimed (废弃)        │
                                │  │ has_friend_display_bonus│
                                │  │   (废弃)                │
                                │  └─────────────────────────┘
                                │
┌─────────────────────────────┐ │
│  exhibition_revenue_records │ │
├─────────────────────────────┤ │
│ id (PK)                     │ │
│ user_id                     │ │
│ star_id                     │ │
│ exhibition_id               │ │
│ asset_id                   │ │
│ slot_id                    │ │
│ slot_owner_uid             │ │
│ slot_type ('own'/'friend') │ │
│ crystal_amount             │ │
│ cycle_start_time           │ │
│ cycle_end_time             │ │
│ status ('claimable'/'...') │ │
│ claimed_at                 │ │
│ created_at                 │ │
└─────────────────────────────┘

┌─────────────────────────────┐
│     task_reset_log          │
├─────────────────────────────┤
│ id (PK)                     │
│ reset_type                  │
│ last_reset_at               │
│ created_at                  │
└─────────────────────────────┘

3.2 表结构

task_definitions任务定义表

CREATE TABLE task_definitions (
    id BIGSERIAL PRIMARY KEY,
    star_id BIGINT,                    -- NULL=全局默认
    task_key VARCHAR(50) NOT NULL,
    task_type VARCHAR(20) NOT NULL,     -- 'daily' | 'onboarding'
    name VARCHAR(100) NOT NULL,
    description TEXT,
    crystal_reward BIGINT DEFAULT 0,
    exp_reward BIGINT DEFAULT 0,
    sort_order INT DEFAULT 0,
    is_active BOOLEAN DEFAULT true,
    created_at BIGINT,
    updated_at BIGINT
);
CREATE UNIQUE INDEX ix_task_def_star_key ON task_definitions(star_id, task_key);

user_daily_task_progress每日任务进度表

CREATE TABLE user_daily_task_progress (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    star_id BIGINT NOT NULL,
    task_key VARCHAR(50) NOT NULL,
    status VARCHAR(20) DEFAULT 'pending',  -- pending/completed/claimed
    completed_at BIGINT,
    claimed_at BIGINT,
    created_at BIGINT,
    updated_at BIGINT
);
CREATE UNIQUE INDEX ix_daily_progress_user_star_key
    ON user_daily_task_progress(user_id, star_id, task_key);

user_onboarding_progress引导任务进度表

CREATE TABLE user_onboarding_progress (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    task_key VARCHAR(50) NOT NULL,
    status VARCHAR(20) DEFAULT 'pending',
    completed_at BIGINT,
    claimed_at BIGINT,
    created_at BIGINT,
    updated_at BIGINT
);
CREATE UNIQUE INDEX ix_onboard_progress_user_key
    ON user_onboarding_progress(user_id, task_key);

user_onboarding_status引导流程状态表

CREATE TABLE user_onboarding_status (
    user_id BIGINT PRIMARY KEY,
    current_stage INT DEFAULT 0,       -- 0=未开始1~N=阶段
    status VARCHAR(20) DEFAULT 'pending',
    -- 以下字段标记废弃,但仍保留
    is_first_login_bonus_claimed BOOLEAN DEFAULT false,
    has_friend_display_bonus BOOLEAN DEFAULT false,
    completed_at BIGINT,
    claimed_at BIGINT,
    created_at BIGINT,
    updated_at BIGINT
);

onboarding_stage_config引导阶段配置表

CREATE TABLE onboarding_stage_config (
    id BIGSERIAL PRIMARY KEY,
    stage INT NOT NULL,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    required_task_keys TEXT[],          -- PostgreSQL 数组类型
    crystal_reward BIGINT DEFAULT 0,
    exp_reward BIGINT DEFAULT 0,
    sort_order INT DEFAULT 0,
    is_active BOOLEAN DEFAULT true,
    created_at BIGINT,
    updated_at BIGINT
);

exhibition_revenue_records展示收益记录表

CREATE TABLE exhibition_revenue_records (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    star_id BIGINT NOT NULL,
    exhibition_id BIGINT NOT NULL,
    asset_id BIGINT NOT NULL,
    slot_id BIGINT NOT NULL,
    slot_owner_uid BIGINT NOT NULL,
    slot_type VARCHAR(20) NOT NULL,    -- 'own' | 'friend'
    crystal_amount BIGINT NOT NULL,
    cycle_start_time BIGINT NOT NULL,
    cycle_end_time BIGINT NOT NULL,
    status VARCHAR(20) DEFAULT 'claimable',
    claimed_at BIGINT,
    created_at BIGINT
);
CREATE INDEX ix_revenue_user_star_status
    ON exhibition_revenue_records(user_id, star_id, status);
CREATE INDEX ix_revenue_star_status
    ON exhibition_revenue_records(star_id, status);

task_reset_log重置日志表

CREATE TABLE task_reset_log (
    id BIGSERIAL PRIMARY KEY,
    reset_type VARCHAR(20) NOT NULL,    -- 'daily'
    last_reset_at BIGINT NOT NULL,
    created_at BIGINT
);

四、API 设计

4.1 移动端 APItaskService HTTP/Triple

每日任务

方法 路径 请求 说明
GET /api/tasks/daily star_id 获取每日任务列表及进度
POST /api/tasks/report-event { event_type, star_id } 上报任务事件(如浏览展品、铸造等)
POST /api/tasks/daily/claim { task_key, star_id } 领取单个任务奖励
POST /api/tasks/daily/claim-all star_id 一键领取所有已完成任务奖励

GET /api/tasks/daily 响应:

{
  "star_id": 1,
  "tasks": [
    {
      "task_key": "daily_login",
      "star_id": 1,
      "name": "每日首次登录",
      "description": "每日首次登录 App",
      "crystal_reward": 20,
      "exp_reward": 20,
      "status": "pending",
      "can_claim": false
    }
  ]
}

POST /api/tasks/report-event 请求:

{
  "event_type": "daily_browse_asset",
  "star_id": 1
}

POST /api/tasks/report-event 响应:

{
  "success": true,
  "task_key": "daily_browse_asset",
  "task_completed": true,
  "message": "任务完成"
}

引导任务

方法 路径 请求 说明
POST /api/tasks/guide/complete { task_key } 上报引导步骤完成
GET /api/tasks/onboarding/status - 获取引导状态
POST /api/tasks/onboarding/advance-stage { target_stage } 切换阶段
POST /api/tasks/onboarding/claim-reward { stage } 领取当前阶段奖励

POST /api/tasks/guide/complete 响应:

{
  "user_id": 123,
  "current_stage": 1,
  "status": "in_progress",
  "stages": [
    {
      "stage": 1,
      "name": "入门引导",
      "required_task_keys": ["square_home", "profile_edit"],
      "crystal_reward": 0,
      "exp_reward": 0
    }
  ]
}

GET /api/tasks/onboarding/status 响应:

{
  "user_id": 123,
  "current_stage": 1,
  "status": "in_progress",
  "stages": [
    {
      "stage": 1,
      "name": "入门引导",
      "required_task_keys": ["square_home", "profile_edit"],
      "crystal_reward": 0,
      "exp_reward": 0
    }
  ]
}

展示收益

方法 路径 请求 说明
GET /api/tasks/exhibition-revenue star_id, status, page, page_size 获取收益记录列表
POST /api/tasks/exhibition-revenue/claim { revenue_id, star_id } 领取单个收益
POST /api/tasks/exhibition-revenue/claim-all star_id 一键领取所有可领取收益

GET /api/tasks/exhibition-revenue 响应:

{
  "items": [
    {
      "id": 123,
      "star_id": 1,
      "exhibition_id": 456,
      "asset_id": 789,
      "slot_id": 1,
      "slot_type": "own",
      "crystal_amount": 100,
      "cycle_start_time": 1712607600000,
      "cycle_end_time": 1712694000000,
      "status": "claimable",
      "can_claim": true
    }
  ],
  "total": 10,
  "page": 1,
  "page_size": 20
}

4.2 Dubbo 内部 RPC

taskService 作为服务端(被调用)

TaskInternalService

service TaskInternalService {
  // 用户注册时调用,创建 onboarding_status + 该 star_id 下的每日任务进度
  rpc InitUserTasks(InitUserTasksRequest) returns (InitUserTasksResponse);

  // 展品到期完成galleryService 调用)
  rpc OnExhibitionCompleted(OnExhibitionCompletedRequest) returns (OnExhibitionCompletedResponse);
}

消息定义:

message InitUserTasksRequest {
  int64 user_id = 1;
  int64 star_id = 2;  // 注册时选择的第一个 star_id
}

message InitUserTasksResponse {
  topfans.common.BaseResponse base = 1;
  bool success = 2;
}

message OnExhibitionCompletedRequest {
  int64 exhibition_id = 1;
  int64 asset_id = 2;
  int64 slot_id = 3;
  int64 occupier_uid = 4;
  int64 occupier_star_id = 5;
  int64 slot_owner_uid = 6;
  int64 crystal_amount = 7;
  int64 start_time = 8;
  int64 expire_at = 9;
}

message OnExhibitionCompletedResponse {
  topfans.common.BaseResponse base = 1;
  int64 revenue_record_id = 2;
}

taskService 作为客户端(调用 userService

userService 新增 RPC

// 更新经验值请求内部RPC调用用于taskService发放经验奖励
message AddExperienceRequest {
  int64 user_id = 1;
  int64 star_id = 2;
  int64 delta = 3;
}

message AddExperienceResponse {
  topfans.common.BaseResponse base = 1;
  int64 new_experience = 2;
}

// 在 service UserSocialService 中添加:
rpc AddExperience(AddExperienceRequest) returns (AddExperienceResponse);

五、业务流程

5.1 每日任务流程

1. 用户注册 → userService 调用 taskService.InitUserTasks
   - 创建 user_onboarding_status新用户标记
   - 创建该 star_id 下的每日任务进度记录status=pending
2. 用户登录 → 前端调用 GET /api/tasks/daily?star_id=xxx
3. 后端返回该用户的每日任务列表(含 status
4. 用户完成行为(如浏览展品)→ 前端调用 POST /api/tasks/report-event
5. 后端自动标记任务完成status=completed
6. 用户点击"领取" → POST /api/tasks/daily/claim
7. 后端验证任务已完成 → 调用 userService.UpdateCrystalBalance → 调用 AddExperience → 更新状态为 claimed
8. 每日 05:00 Asia/Shanghai
   a. Advisory Lock 获取锁pg_advisory_lock(YYYYMMDD)
   b. 查询 task_reset_log如今天已有记录则跳过
   c. 所有非 pending 状态的记录恢复为 pending
   d. 记录 task_reset_log
   e. 释放锁

5.2 引导任务流程

1. 用户首次登录 → 前端调用 GET /api/tasks/onboarding/status
2. 返回 { current_stage: 0, status: 'pending', stages: [...] }
3. 前端根据 stage 配置显示引导步骤
4. 用户完成引导步骤(如 square_home
5. → POST /api/tasks/guide/complete { task_key: "square_home" }
6. 后端更新 user_onboarding_progress.status = 'completed'
7. 前端引导流程中,用户点击"进入下一阶段"
8. → POST /api/tasks/onboarding/advance-stage { target_stage: 2 }
9. 后端检查 stage 1 所有 task_key 是否都已 completed
   - 如未全部完成,返回错误
   - 如全部完成current_stage++,返回最新状态
10. 前端调用 POST /api/tasks/onboarding/claim-reward 领取阶段奖励
11. 重复 3-10直到所有引导完成

5.3 展示收益流程

1. galleryService 的 CleanupWorker 扫描到过期展品
2. → 调用 taskService.OnExhibitionCompleted RPC
3. taskService 创建 exhibition_revenue_recordsstatus=claimable
4. 每日 05:00紧接重置后
   a. 查询所有 status=claimable 的记录
   b. 分批处理(每批 N 条,可配置)
   c. 调用 userService.UpdateCrystalBalance 发放水晶
   d. 成功则更新 status=claimed失败则重试 N 次
   e. 仍失败则标记 status=failed对用户不可见运营可查
5. 用户打开移动端 → GET /api/tasks/exhibition-revenue
   - 前端只显示 claimable 和 claimed 状态的记录
   - failed 记录对用户不可见
6. 用户点击领取 → POST /api/tasks/exhibition-revenue/claim
7. 后端调用 userService.UpdateCrystalBalance → 更新状态

六、分页规范

所有列表查询统一分页参数:

参数 类型 说明
page int 页码,从 1 开始
page_size int 每页条数,最大 100

响应结构:

{
  "items": [...],
  "total": 100,
  "page": 1,
  "page_size": 20
}

七、Worker 设计

7.1 DailyResetWorker + RevenueAutoClaimWorker

共用一个 Worker每天 05:00 Asia/Shanghai 执行。

// 伪代码
func (w *Worker) run() {
    // 尝试获取锁日期作为锁ID
    lockID := time.Now().Format("20060102")  // 如 "20230409"
    if !w.acquireAdvisoryLock(lockID) {
        return  // 其他实例在执行
    }
    defer w.releaseAdvisoryLock(lockID)

    // 1. 执行每日任务重置
    w.resetDailyTasks()

    // 2. 执行展示收益自动发放
    w.autoClaimExhibitionRevenue()
}

func (w *Worker) resetDailyTasks() {
    // 查询 task_reset_log如今天已有记录则跳过
    // 更新所有 status != 'pending' 的记录为 'pending'
    // 记录 task_reset_log
}

func (w *Worker) autoClaimExhibitionRevenue() {
    // 查询所有 status='claimable' 的记录
    // 分批处理batch_size 可配置)
    // 每批:调用 userService.UpdateCrystalBalance
    //   - 成功:更新 status='claimed'
    //   - 失败:重试 N 次(可配置),仍失败标记 status='failed'
    // 每条记录处理结果保存到日志
}

7.2 Advisory Lock 设计

  • 锁 key 日期格式 YYYYMMDD(如 20230409
  • 获取锁: pg_try_advisory_lock(lockID)
  • 释放锁: pg_advisory_unlock(lockID)
  • 作用: 保证多实例环境下每天只执行一次重置和自动发放

八、activity-admin 页面

页面 路由 功能
任务定义列表 /tasks/definitions 查看、新建、编辑、删除、启用/禁用任务定义
每日任务进度 /tasks/daily-progress 查询各用户的每日任务完成情况
引导任务进度 /tasks/onboarding-progress 查询各用户的引导任务完成情况
任务统计 /tasks/stats 任务完成率/领取率统计图表,支持 star_id、时间范围筛选
手动重置 /tasks/reset 手动触发每日任务重置
收益记录 /tasks/revenue 查看展示收益记录(含 failed支持手动补发

统计页面指标:

  • 每日任务:完成人数、领取人数、完成率、领取率
  • 引导任务:各 stage 完成人数、总体完成率
  • 收益统计:总发放水晶数、待领取水晶数、已领取水晶数

筛选维度:

  • star_id
  • 时间范围近7天、近30天、自定义
  • 任务类型daily/onboarding

九、项目结构

9.1 目录结构

backend/
├── proto/
│   ├── user.proto          # 修改:新增 AddExperience RPC
│   └── task.proto          # 新增TaskInternalService
│
├── services/
│   ├── taskService/        # 新增
│   │   ├── main.go
│   │   ├── config/
│   │   │   └── task_config.go
│   │   ├── repository/
│   │   │   └── task_repository.go
│   │   ├── service/
│   │   │   ├── daily_task_service.go
│   │   │   ├── onboarding_service.go
│   │   │   └── exhibition_revenue_service.go
│   │   ├── provider/
│   │   │   ├── task_mobile_provider.go    # 移动端 API
│   │   │   └── task_internal_provider.go   # 内部 RPC
│   │   ├── worker/
│   │   │   └── daily_reset_worker.go
│   │   └── client/
│   │       └── user_rpc_client.go
│   │
│   └── userService/        # 修改
│       ├── repository/
│       │   └── fan_profile_repository.go  # 新增 UpdateExperience
│       ├── service/
│       │   └── user_service.go            # 新增 AddExperience
│       └── provider/
│           ├── user_provider.go           # 新增 AddExperience
│           └── unified_provider.go        # 新增 AddExperience
│
├── pkg/
│   └── proto/
│       ├── user/
│       │   └── *.go         # 重新生成
│       └── task/
│           └── *.go          # 新生成
│
└── scripts/
    └── v001_init_task_tables.sql

9.2 前端文件activity-admin

frontend/src/
├── api/
│   └── admin.js            # 修改:新增任务相关 API
├── views/
│   ├── TaskDefinitionList.vue
│   ├── TaskProgress.vue
│   ├── TaskStats.vue
│   ├── TaskReset.vue
│   └── RevenueList.vue
└── router/
    └── index.js            # 修改:新增路由

十、后续迭代项

以下内容在当前设计中预留扩展点,后续可根据业务需求添加:

  1. 引导任务细分 - square_home 等 key 是否需要与 star_id 关联
  2. 任务事件扩展 - ReportTaskEvent 的 event_type 可继续扩展
  3. 收益周期细分 - 当前 cycle_start/end_time 为基础字段,可扩展 cycle_name 等
  4. 统计图表扩展 - 当前预留 ECharts 位置,可扩展更多图表类型
  5. 手动重置扩展 - 当前支持全局重置,可扩展按 star_id 重置

十一、错误码规范

复用现有 BaseResponse.code 体系,不新增自定义业务错误码。

场景 处理方式
领取未完成任务 静默返回成功,前端根据 status 阻止
领取已领取任务 静默返回成功,前端根据 status 阻止
阶段切换但任务未完成 返回错误,前端提示
RPC 超时 记录日志,不自动重试(可手动补发)
重置时其他实例在执行 跳过本次执行