先确认Redis连接配置或网络是否通畅:检查redis://地址格式(Docker中localhost需换宿主机IP或服务名),用redis-cli -u验证连通性,确认ACL权限;任务不执行需检查是否启动worker进程且显式调用srv.Run()。

asynq.NewClient 连不上 Redis 怎么快速定位
连不上不是 asynq 的问题,大概率是 Redis 连接配置或网络没通。先确认 redis:// 地址格式对不对:本地开发常用 redis://localhost:6379/0,但 Docker 或远程环境里 localhost 会指向容器自身,得换成宿主机 IP(如 redis://172.17.0.1:6379/0)或服务名(如 redis://redis:6379/0)。
常见错误现象:failed to dial redis: dial tcp [::1]:6379: connect: connection refused —— 说明 asynq 根本没找到 Redis 实例;redis: connection closed 则可能是认证失败或 timeout 太短。
- 检查
asynq.NewClient初始化时传的asynq.RedisClientOpt是否包含正确Addr和可选的Password - 用
redis-cli -u redis://localhost:6379/0 ping手动验证连通性,别跳过这步 - 如果 Redis 启用了 ACL(6.0+),确保用户有
+ping、+replconf、+psubscribe权限,asynq 内部依赖这些
任务注册后不执行,是不是没启 worker
asynq 不像 Celery 那样自动拉起 worker。client.Enqueue 只是把任务塞进 Redis,必须另起一个进程跑 asynq.ServeMux + asynq.Server 才会消费。漏掉这步,任务就永远卡在 pending 状态。
使用场景:Web 请求中触发异步发邮件、生成报表、清理缓存——这些逻辑写在 handler 里没问题,但执行它们的 worker 必须独立部署,不能和 HTTP server 共用同一个 main() 且没调 server.Run()。
立即学习“go语言免费学习笔记(深入)”;
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 必须显式创建并启动 server:
srv := asynq.NewServer(...); srv.Run(mux)—— 这是阻塞调用,不能漏 - 别用
go srv.Run(mux)异步启动,主 goroutine 立即退出,整个进程就结束了 -
asynq.Server默认并发是 10,如果任务密集但 CPU 低,可以调高Concurrency;反之高 CPU 场景建议压到 2–4 避免线程争抢 - 别在 worker 里直接用
log.Fatal或panic后没recover,会导致整个 worker 进程退出,后续任务全积压
handler 注册失败或找不到 task type 怎么排查
注册 handler 只是定义了“这个任务类型该交给哪个函数处理”,但真正驱动消费的是 asynq.Server 实例。它需要你手动调用 Start 并保持进程运行 —— 它不是 goroutine 自启,也不是 daemon 进程。
常见 panic:handler not found for task type 发生在 srv.Run() 后消费任务时,说明任务入队了,但 asynq 运行时找不到对应 handler —— 常见于类型名拼写不一致或注册时机错误。
- 确保
srv.Mux().Handle("send_email", &EmailHandler{})中第一个参数(task type)和入队时asynq.NewTask("send_email", payload)的字符串完全一致,大小写敏感 - Handler 结构体方法必须叫
ProcessTask,签名固定为func(*asynq.Context, *asynq.Task) error,少一个星号或改名都会导致反射失败 - 所有
HandleFunc统一收口到一个task/handler.go文件里,避免在 HTTP handler 或 CLI 命令中动态注册 - 重复注册会 panic:
handler already registered,注册必须发生在 server 启动前,且仅一次
任务投递后 Redis 里看不到数据,是不是静默失败了
asynq 默认情况下,asynq.NewClient 使用的是 asynq.DefaultRedisClientOpt,但如果你没显式传入 *redis.Options,它会尝试连接 localhost:6379 —— 很多本地开发环境根本没起 Redis,或者用了 Docker 网络别名(比如 redis:6379),导致任务静默失败。
检查是否真有 Redis 实例在运行:redis-cli ping 返回 PONG;发任务后,用 redis-cli keys "asynq:*" 查看是否有 asynq:default 这类 key;没有说明连接失败或任务被丢弃(Enqueue 返回 error 但你没检查)。
- 初始化 client 时必须显式配置地址:
cli := asynq.NewClient(asynq.RedisClientOpt{Addr:"redis:6379"}) -
asynq.NewTask的 payload 必须 JSON 可序列化且导出(首字母大写),字段类型只能是string、int、bool、map[string]interface{}、[]interface{} - 默认重试 25 次,易致任务“消失”于 retry 队列;发任务时加
asynq.MaxRetry(3)控制上限更可控 - 任务 ID 用
asynq.TaskID("uid-123")配合 RedisSETNX或数据库唯一索引做幂等判断,避免重复消费
最常被忽略的点:worker 进程要和 producer 进程分开部署,一个进程只负责发任务,另一个(或多个)专门跑 srv.Run;同时,asynq.Server 启动时连不上 Redis 会直接 panic,而不是返回 error —— 它把连接可靠性交给了你,得自己预检或封装重试逻辑。

















