feat: 添加监控仪表盘

- 新增 Lit.js 组件化 UI (ui/ 目录)
  - tasks-chart: 带十字准星和拖拽选择的图表
  - queue-table: 队列列表,支持暂停/恢复
  - queue-modal: 队列详情弹窗,支持任务重试
  - time-range-picker: Prometheus 风格时间选择器
  - help-tooltip: 可复用的提示组件

- HTTPHandler 功能
  - SSE 实时推送 (stats + queues)
  - 队列暂停/恢复 API
  - 任务重试 API
  - 时间范围查询 API

- Inspector 改进
  - Prometheus 风格单表存储
  - 集成到 Start/Stop 生命周期
  - 新增 PauseQueue/UnpauseQueue/RunTask 方法

- 代码重构
  - Start 函数拆分为小函数
  - 优雅关闭流程优化

- 其他
  - 忽略 SQLite 数据库文件
  - example 添加延迟/定点任务示例
This commit is contained in:
2025-12-09 19:58:18 +08:00
parent c88bde7b11
commit 1f9f1cab53
17 changed files with 3665 additions and 787 deletions

26
task.go
View File

@@ -87,13 +87,21 @@ func (t *Task[T]) Publish(ctx context.Context, data T, options ...PublishOption)
// 构建任务选项
opts := []asynq.Option{
asynq.Queue(t.Queue), // 设置队列名称
asynq.Group(t.Group), // 设置任务组
asynq.MaxRetry(t.MaxRetries), // 设置最大重试次数
asynq.TaskID(xid.New().String()), // 生成唯一任务ID
asynq.Timeout(t.TTR), // 设置超时时间
asynq.Retention(time.Hour * 24), // 设置结果保留24小时
}
// 只有设置了 TTR 才添加超时选项,避免 TTR=0 导致立即超时
if t.TTR > 0 {
opts = append(opts, asynq.Timeout(t.TTR))
}
// 只有设置了 Group 才添加分组选项
if t.Group != "" {
opts = append(opts, asynq.Group(t.Group))
}
// 应用用户自定义选项
for _, option := range options {
if opt := option(); opt != nil {
@@ -126,14 +134,15 @@ func (t *Task[T]) ProcessTask(ctx context.Context, tsk *asynq.Task) error {
// 根据配置添加数据参数
if t.inputData {
// 创建数据类型的指针实例
dataValue := reflect.New(t.dataType)
// 创建数据类型的指针实例用于反序列化
dataPtr := reflect.New(t.dataType)
// 反序列化任务载荷
err := json.Unmarshal(tsk.Payload(), dataValue.Interface())
err := json.Unmarshal(tsk.Payload(), dataPtr.Interface())
if err != nil {
return err
}
in = append(in, dataValue)
// 传递值类型而非指针,因为 Handler 期望的是值类型
in = append(in, dataPtr.Elem())
}
// 通过反射调用处理器函数
@@ -141,7 +150,10 @@ func (t *Task[T]) ProcessTask(ctx context.Context, tsk *asynq.Task) error {
// 处理返回值
if t.returnError {
// Register 已确保返回类型为 error无需类型断言
// 当返回值为 nil 时Interface() 返回 nil不能直接类型断言
if out[0].IsNil() {
return nil
}
return out[0].Interface().(error)
}
return nil