直接用taskq模块可避免自研调度器的密集踩坑,它已封装队列、重试、分布式锁、批量消费等能力,50行内即可构建生产可用多节点任务系统。

直接用 taskq 模块,别自己从 Redis List + etcd 锁开始造轮子——它已封装好队列、重试、分布式锁、批量消费等关键能力,50 行内就能跑通一个生产可用的多节点任务系统。
为什么不用自己写调度器核心逻辑
自己实现 RPopLPush + etcd Lease + 任务状态机,看似可控,实际踩坑密集:比如 RPopLPush 成功但 JSON 反序列化失败,任务就卡在 processing 队列里没人清理;又或者 etcd lease 续约失败后 worker 还在偷偷执行,导致重复消费。而 taskq 在 redisq/queue.go 里把这类边界全收口了——它用 BRPOPLPUSH 阻塞拉取,失败时自动回滚到 pending,重试前先校验 retry_count 和 next_retry_at 字段,不依赖外部定时器轮询。
常见错误现象:taskq 默认启用幂等消费,但如果你在 Process 方法里没返回 error,它会认为成功并删除消息;结果数据库写了一半崩溃,任务就丢了。必须确保业务逻辑的 error 路径完整透出。
- 使用场景:适合中小规模异步任务(邮件发送、通知推送、轻量 ETL),日均百万级以下
- 性能影响:开启
BatchSize=10后,IO 吞吐提升 3–4 倍,但单任务延迟增加最多 200ms - 兼容性:Redis 6.2+ 支持
XPENDING的话,可无缝切换到 Stream 后端,无需改业务代码
三步接入 taskq(以 Redis 为例)
不用改现有服务结构,只要加一个独立 consumer 进程或复用主进程 goroutine。
- 安装:
go get github.com/hyperjiang/taskq(注意是 hyperjiang 分支,官方原 repo 已归档) - 初始化队列:
queue := redisq.NewFactory().CreateQueue(&redisq.Config{Addr: "redis://localhost:6379/0"}),密码需显式传Password字段,URL 形式不解析 auth - 注册处理器:
queue.Register("send_email", &EmailSender{}),其中EmailSender必须实现Process(ctx context.Context, *taskq.Task) error,且不能忽略ctx.Done()——超时中断靠它触发
启动消费:queue.StartConsumers(4) 即开 4 个并发 worker。它会自动监听 taskq:send_email 列表,失败任务按 RetryPolicy 指数退避(默认 1s→2s→4s… 最大 5 次)。
etcd 协调不是必须项,但节点上线要同步任务就得加
纯 taskq 是无状态 worker,新节点启动后不会主动拉取 pending 队列里的积压任务,只等下一次入队才分发。这在灰度扩缩容时会导致处理延迟飙升。
解决方案是加一层轻量协调:新节点启动时,用 etcd 的 Get + CompareAndSwap 去抢注 /workers/active/{node_id},抢成功后立即触发一次 queue.BulkPop("pending", 100) 手动捞取积压。不需要长期持有 lease,抢到即用完即删。
容易踩的坑:taskq 的 BulkPop 不保证原子性,若中途 panic,部分任务可能已出队但未被处理。务必配合 defer queue.RecoverBulk() 回滚未完成批次。
别忽略任务定义里的 metadata 字段
taskq.Task 结构体里有 Metadata map[string]string,它不参与序列化传输,只在内存中流转。这是唯一能安全传递上下文的地方——比如你用 Gin 处理 HTTP 请求后生成任务,想把 X-Request-ID 透传给 worker 做日志串联,就该塞进这里,而不是往 Payload 里硬编码。
另一个关键点:taskq 对 Payload 只做 JSON 序列化,字段增减会导致反解失败。如果业务需要长期兼容,必须用 json.RawMessage 包一层,或切到 Protobuf 后端(protobuq 模块)。
复杂点在于:当任务链路涉及多个系统(比如 XXL-JOB 触发 → taskq 执行 → 再投递到 NATS),metadata 无法跨中间件传递,这时得靠全局 traceID 存 DB 或 Redis,靠它关联各环节日志。这点文档很少提,但线上排障时最痛。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











