task/README.md

118 lines
4.2 KiB
Markdown
Raw Permalink Normal View History

2026-05-10 21:19:30 +08:00
# @go/task
> **Maintainer Statement:** 本项目完全由 AI 维护。任何改动均遵循代码质量与性能的最佳实践。
## 🎯 设计哲学
`@go/task` 是一个简单、易用且高效的任务调度引擎。它建立在 `robfig/cron` 之上提供了更丰富的任务管控能力如并发策略控制、生命周期管理和超时控制。设计严格遵循单一职责原则SRP剔除了不相关的状态共享模块让任务调度更加专注。
**v1.2.0 重大更新**:基础设施对齐,`Scheduler` 实现 `Service` 接口,移除顶层 `Start/Stop` 函数。
2026-05-10 21:19:30 +08:00
## 📦 安装
```bash
go get apigo.cc/go/task
```
## 💡 快速开始
2026-05-10 21:19:30 +08:00
### 1. 注册任务
任务函数必须遵循 `func(ctx context.Context) error` 签名,以便处理超时和优雅退出。
2026-05-10 21:19:30 +08:00
```go
import "apigo.cc/go/task"
// 简单注册(使用默认配置)
task.Add("CleanLog", "@daily", func(ctx context.Context) error {
2026-05-10 21:19:30 +08:00
// 执行清理逻辑
return nil
})
// 带配置注册
task.Add("Report", "@every 1m", func(ctx context.Context) error {
// ...
return nil
}, task.Config{
Policy: task.PolicySkip, // 如果上次还没跑完,跳过本次
Timeout: 5 * time.Second, // 单次执行超时
SuppressSuccessLog: true, // 抑制默认 success 日志,由任务自行汇报
2026-05-10 21:19:30 +08:00
})
```
### 2. 生命周期管理
`Scheduler` 实现了标准的 `Service` 接口,推荐通过基础设施管理。
2026-05-10 21:19:30 +08:00
```go
// 启动默认调度器
task.DefaultScheduler.Start(ctx, logger)
2026-05-10 21:19:30 +08:00
// 手动触发任务执行
task.Run("CleanLog")
2026-05-10 21:19:30 +08:00
// 优雅停止:取消所有任务 Context并等待任务返回由 ctx 控制超时)
task.DefaultScheduler.Stop(ctx)
2026-05-10 21:19:30 +08:00
```
### 3. 任务控制
可以通过对象或全局方法管理任务状态。
2026-05-10 21:19:30 +08:00
```go
tk := task.Get("CleanLog")
2026-05-10 21:19:30 +08:00
tk.Disable() // 挂起任务
tk.Enable() // 恢复任务
tk.Remove() // 彻底移除
2026-05-10 21:19:30 +08:00
task.Disable("CleanLog") // 按名称挂起,未知任务返回 false
task.Enable("CleanLog") // 按名称恢复,未知任务返回 false
// 查询
tasks := task.List()
2026-05-10 21:19:30 +08:00
```
### 4. 任务上下文日志
调度器从生命周期管理器接收父 Logger并为每次实际执行创建独立 Trace。任务函数可直接从 Context 取得本次运行的 Logger
```go
task.Add("Report", "@every 1m", func(ctx context.Context) error {
logger := task.Logger(ctx)
logger.Info("report generated", "count", 12)
return nil
})
```
空轮询任务可使用 `SuppressSuccessLog` 避免无效磁盘日志失败、Panic 和未抑制的成功日志均沿用本次运行的 Trace。
### 5. Redis 可靠队列
`task/queue` 按全局队列名使用约定连接 `redis.task`,调用方无需持有 Redis Client 或 Context
```go
import "apigo.cc/go/task/queue"
_ = queue.Add("translation", item)
items, _ := queue.Fetch("translation", "default", 50)
// processing 中存在未完成批次时Fetch 忽略 n 并返回原批次。
// 业务成功后一次性确认当前消费者的 processing。
_ = queue.Finish("translation", "default")
// 持久化延迟任务;到期后由 Fetch 提升到 pending。
_ = queue.AddAfter("translation", item, 30*time.Second)
```
队列使用 `pending`、按消费者隔离的 `processing` 和 Sorted Set `delayed` 三条持久化通道。任务失败时不调用 `Finish`,下一次 `Fetch` 会恢复同一 processing 批次。
`Fetch` 使用标准 `LMOVE` 原子地把任务转入 processing。为兼容要求目标 List 预先存在的 SugarDB首次移动前会用一个立即弹出的内部标记初始化空 List该标记不会保留在 processing也不会返回给调用方。标准 Redis 会在弹出最后一个元素后删除 key随后的 `LMOVE` 会按标准语义创建目标 List。
## 🛡️ 健壮性与安全
2026-05-10 21:19:30 +08:00
* **Panic Recovery**: 框架内部自动捕获任务执行中的 Panic并记录堆栈日志确保调度引擎持续稳定。
* **Context 传播**: 任务内部应监听 `ctx.Done()` 以响应系统的停止信号。
* **标准化日志**: 集成 `@go/log`,为每次实际执行创建独立 Trace并记录成功、失败含耗时以及 Panic 信息。
2026-05-10 21:19:30 +08:00
## 🧪 验证状态
测试全部通过,性能达标。
详见:[TEST.md](./TEST.md)