Files
OpenFlare/.agent/skills/new-async-task/SKILL.md
T
2026-06-18 15:24:48 +08:00

5.4 KiB
Raw Blame History

name, description
name description
new-async-task Wavelet 项目专用:新增或修改 Asynq 异步任务、后台任务、定时任务、任务元数据、TaskHandler、TaskParam、PayloadValidator、AppendLog、任务重试、任务执行记录或 Admin 任务 API 时必须使用。

异步任务开发

开始前阅读根目录 AGENTS.md。只修改任务相关链路,遵守项目路由、日志、数据库迁移和质量门禁要求。

开始前

按任务范围检查当前实现:

  • internal/task/handler.go:TaskHandler、TaskResult、PayloadValidator
  • internal/task/meta.go:TaskMeta、TaskParam
  • internal/task/executor.go:下发、执行、日志、重试、OnTaskCompleted 订阅
  • internal/task/handlers/register.go:Handler 和元数据注册(由 bootstrap 调用)
  • internal/bootstrap/bootstrap.go:任务注册与进程级装配入口
  • internal/task/worker/worker.go:Worker 路由和队列
  • internal/task/scheduler/scheduler.go:定时调度
  • internal/apps/admin/task/routers.go:Admin 任务 API
  • internal/model/task_execution.go:执行记录和日志持久化

需要模板时阅读 references/CODE-EXAMPLES.md。

实现要求

任务定义

  • 在 internal/apps/<module>/tasks.go 定义任务类型、Admin 任务类型和 TaskMeta。
  • Asynq 任务类型使用 <module>:<action> 格式。
  • 完整设置 Type、AsynqTask、Name、Description、MaxRetry、Queue、Retryable。
  • 有参数任务必须定义 payload struct。
  • TaskParam.Name 必须与 payload JSON tag 一致。
  • TaskParam 只描述前端表单,不代替服务端校验。

Handler

  • Handler 必须实现 task.TaskHandler。
  • 有参数任务必须实现 task.PayloadValidator,负责校验和标准化 Admin 下发参数。
  • Execute 必须再次解析 payload;不要假设入口一定经过 Admin 校验。
  • 成功返回 &task.TaskResult{Message: ..., Detail: ...}。
  • 失败返回 error,由任务框架处理状态和重试。
  • 不要吞掉关键错误。
  • 复杂 SQL 放到 internal/model/ 或模块内的业务服务层(如 internal/apps/<module>/service.go 或 logics.go)。

注册

  • 在 internal/task/handlers/register.go 同时注册 Handler 和 TaskMeta。
  • 不要在其他位置单独注册任务。
  • 禁止在业务包 routers.go 或 init() 中调用 task.RegisterHandler;统一由 bootstrap.RegisterTasks() → taskhandlers.Register() 在进程启动时装配。
  • 任务完成钩子(如 push 通知)通过 task.OnTaskCompleted 注册,在 bootstrap.RegisterTaskListeners() 中装配(Worker/all 进程)。

进程装配分工

进程 注册入口
api cmd/api.go → bootstrap.RegisterAPI()(含 RegisterTasks)
worker worker.StartWorker() → bootstrap.RegisterWorker()(含 RegisterTasks + RegisterTaskListeners)
scheduler scheduler.StartScheduler() → bootstrap.RegisterScheduler()
all cmd/all.go → bootstrap.RegisterAll()

所有 Register* 使用 sync.Once,重复调用安全。

测试

  • 依赖已注册任务类型或 Handler 的测试(如 internal/apps/admin/task/routers_test.go),必须在 setup 中显式调用 bootstrap.RegisterTasks()。
  • 不得依赖 init() 副作用或 import 链触发注册。

日志要求

  • 在 TaskHandler.Execute 中使用 task.AppendLog(ctx, format, args...)。
  • 记录任务开始、参数摘要、批次进度、关键状态、可继续错误和完成摘要。
  • 批量处理按批次记录;禁止为大循环中的每条数据写日志。
  • 不要直接修改任务日志的 Redis key 或 w_task_executions.log。

日志框架约束:

  • 执行状态实时写入数据库:pending、running、succeeded、failed。
  • 实时日志写入 Redis,每个任务最多保留最近 1000 行。
  • Redis 日志 TTL 为 24 小时,每次追加时刷新。
  • 查询时优先返回 Redis 日志,Redis 不存在时读取数据库。
  • 任务成功或自动重试耗尽后,将日志写入数据库并删除 Redis 缓冲。
  • 自动重试期间保留同一 taskID 的 Redis 日志。

重试要求

  • Handler 返回 error 以触发 Asynq 自动重试。
  • 不要在 Handler 内自行实现重复重试循环。
  • Admin 手动重试只允许:
    • 原任务状态为 failed
    • Retryable=true
    • RetryCount < MaxRetry
  • 修改重试行为时同时检查:
    • internal/task/executor.go
    • internal/model/task_execution.go
    • internal/apps/admin/task/routers.go
    • 前端任务执行列表

定时任务

  • 默认定时任务必须通过 Goose SQL 迁移写入 schedules。
  • PostgreSQL 和 SQLite 迁移必须同时提供。
  • 初始化 SQL 必须幂等。
  • 涉及迁移时使用 database-migration skill。

Admin API

  • Handler 放在现有 Admin task 模块或 internal/apps/admin/<module>/。
  • 路由只在 internal/router/router.go 注册。
  • 响应保持 { "error_msg": "", "data": ... }。
  • 分页数据保持 { "total": 0, "results": [] }。
  • Swagger 注释必须完整;API 变化后运行 make swagger。

前端

  • 仅任务元数据变化时,优先复用现有动态任务表单,不新增页面。
  • API 调用必须通过 frontend/lib/services/。
  • 修改 shadcn/ui 时使用 shadcn skill。
  • 不使用 any。
  • 页面根容器使用 w-full,不添加页面级 max-w-*。