Asynq:简单可靠的Go分布式任务队列

Asynq:Go分布式任务队列

Asynq是一个基于Redis的Go语言分布式任务队列库,设计简单易用且可靠高效。它支持任务的异步处理、调度、重试和监控,是构建分布式系统的理想选择。

功能特性

  • 任务调度:支持立即执行或定时执行任务
  • 重试机制:自动重试失败的任务,可配置重试策略
  • 优先级队列:支持加权优先级和严格优先级两种队列模式
  • 任务聚合:将多个任务聚合成单个任务处理,提高效率
  • 可靠性保障:保证至少一次执行,支持任务恢复机制
  • 监控管理:提供丰富的CLI工具和Web仪表板监控任务状态
  • 分布式支持:支持多工作节点水平扩展

安装指南

前提条件

  • Go 1.22 或更高版本
  • Redis 5.0 或更高版本

安装方式

# 安装Asynq库
go get -u github.com/hibiken/asynq

# 安装CLI工具
go install github.com/hibiken/asynq/tools/asynq@latest

依赖配置

在项目中引入Asynq:

import "github.com/hibiken/asynq"

使用说明

基本用法

// 创建Redis连接配置
redisConn := asynq.RedisClientOpt{
    Addr:     "localhost:6379",
    Password: "", // 无密码
    DB:       0,  // 默认数据库
}

// 创建客户端
client := asynq.NewClient(redisConn)
defer client.Close()

// 创建任务
task := asynq.NewTask("email:send", []byte(`{"to": "user@example.com"}`))

// 立即执行任务
info, err := client.Enqueue(task)
if err != nil {
    log.Fatal(err)
}

// 延迟执行任务(1分钟后)
info, err = client.Enqueue(task, asynq.ProcessIn(1*time.Minute))

创建任务处理器

// 定义任务处理器
func handleEmailTask(ctx context.Context, task *asynq.Task) error {
    var payload map[string]interface{}
    if err := json.Unmarshal(task.Payload(), &payload); err != nil {
        return err
    }
    // 处理邮件发送逻辑
    return sendEmail(payload["to"].(string))
}

// 创建服务器
srv := asynq.NewServer(redisConn, asynq.Config{
    Concurrency: 10, // 并发工作协程数
    Queues: map[string]int{
        "critical": 6, // 优先级权重
        "default":  3,
        "low":      1,
    },
})

// 注册处理器并启动服务器
mux := asynq.NewServeMux()
mux.HandleFunc("email:send", handleEmailTask)

if err := srv.Run(mux); err != nil {
    log.Fatal(err)
}

任务调度

// 创建调度器
scheduler := asynq.NewScheduler(redisConn, nil)

// 注册定时任务(每天凌晨执行)
entryID, err := scheduler.Register("* * * * *", asynq.NewTask("daily:report", nil))
if err != nil {
    log.Fatal(err)
}

// 启动调度器
if err := scheduler.Start(); err != nil {
    log.Fatal(err)
}

核心代码

任务定义与处理

// Task表示要执行的工作单元
type Task struct {
    typename string    // 任务类型名称
    payload  []byte    // 任务负载数据
    opts     []Option  // 任务选项
    w        *ResultWriter // 结果写入器
}

// NewTask创建新任务
func NewTask(typename string, payload []byte, opts ...Option) *Task {
    return &Task{
        typename: typename,
        payload:  payload,
        opts:     opts,
    }
}

// Handler接口定义任务处理方法
type Handler interface {
    ProcessTask(context.Context, *Task) error
}

// HandlerFunc类型适配器
type HandlerFunc func(context.Context, *Task) error

func (f HandlerFunc) ProcessTask(ctx context.Context, task *Task) error {
    return f(ctx, task)
}

服务器核心组件

// Server负责任务处理和生命周期管理
type Server struct {
    logger   *log.Logger
    broker   base.Broker      // Redis代理
    state    *serverState     // 服务器状态
    
    // 各个功能组件
    forwarder     *forwarder     // 转发器:移动任务到待处理状态
    processor     *processor     // 处理器:执行任务处理
    heartbeater   *heartbeater   // 心跳检测:维持 worker 活跃状态
    recoverer     *recoverer     // 恢复器:处理失败任务恢复
    healthchecker *healthchecker // 健康检查:监控系统健康状态
    janitor       *janitor       // 清理器:删除过期已完成任务
    aggregator    *aggregator    // 聚合器:任务聚合处理
}

// 启动服务器所有组件
func (srv *Server) Start(handler Handler) error {
    srv.setup(handler)
    srv.wg.Add(1)
    go srv.run()
    return nil
}

任务聚合器实现

// aggregator负责检查组并将任务聚合
type aggregator struct {
    logger      *log.Logger
    broker      base.Broker
    client      *Client
    done        chan struct{}      // 停止信号通道
    queues      []string           // 要检查的队列列表
    gracePeriod time.Duration      // 聚合宽限期
    maxDelay    time.Duration      // 最大延迟时间
    maxSize     int                // 最大聚合大小
    ga          GroupAggregator    // 用户提供的聚合器
    interval    time.Duration      // 检查间隔
    sema        chan struct{}      // 信号量控制并发数
}

// 执行聚合检查
func (a *aggregator) aggregate(t time.Time) {
    defer func() { <-a.sema }() // 释放令牌
    for _, qname := range a.queues {
        groups, err := a.broker.ListGroups(qname)
        if err != nil {
            a.logger.Errorf("Failed to list groups in queue: %q", qname)
            continue
        }
        // 检查每个组的聚合条件
        for _, gname := range groups {
            a.processGroup(qname, gname, t)
        }
    }
}

Redis数据操作

// RDB封装与Redis的交互
type RDB struct {
    client          redis.UniversalClient
    clock           timeutil.Clock
    queuesPublished sync.Map
}

// 任务入队操作
func (r *RDB) Enqueue(ctx context.Context, msg *base.TaskMessage) error {
    op := errors.Op("rdb.Enqueue")
    // 验证消息有效性
    if err := msg.Validate(); err != nil {
        return errors.E(op, errors.FailedPrecondition, err.Error())
    }
    // 执行Redis脚本入队
    return r.runScript(ctx, op, enqueueCmd, 
        []string{base.PendingKey(msg.Queue)}, 
        msg, time.Now().Unix(), msg.Queue)
}

Asynq提供了完整的分布式任务处理解决方案,从任务创建、调度、执行到监控管理,每个环节都经过精心设计和优化,确保系统的可靠性和高性能。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

posted @ 2025-08-27 15:06  qife  阅读(6)  评论(0)    收藏  举报