go语言使用redis实现异步任务
目前go语言有一些比较可靠的异步队列的开源组件比如asynq、Machinery等,但是组件一个有学习成本,二是出现问题的时候比较头疼,排查起来比较费时间还要分析源码,所以自己比较倾向于写一个轻量级。
此过程使用的是redis的list,左进右出,一般生产者使用lpush压入数据,消费者调用rpop取出数据。这个具体看自己的需求,如果任务是可以做到幂等操作的,可以使用lrange+ltrim替代lpop,在处理成功后调用ltrim,这样可做到至少处理一次。
首先在应用启动的时候初始话加载redis连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package initialization import ( "context" "fmt" "log" "time" "github.com/go-redis/redis/v8" ) var RedisClient *redis.Client type RedisOptoins struct { Host string `yaml: "host" json: "host" ` Port int `yaml: "port" json: "port" ` DB int `yaml: "db" json: "db" ` PoolSize int `yaml: "pool_size" json: "pool_size" ` MinIdle int `yaml: "min_idle" json: "min_idle" ` } func NewRedisClient() *redis.Client { redis_config := Config.Redis RedisClient = redis.NewClient(&redis.Options{ Addr: fmt.Sprintf( "%s:%d" , redis_config.Host, redis_config.Port), PoolSize: redis_config.PoolSize, MinIdleConns: redis_config.MinIdle, DB: redis_config.DB, PoolTimeout: time.Second * 5, WriteTimeout: time.Second * 5, IdleCheckFrequency: 60 * time.Second, //闲置连接检查的周期,默认为1分钟,-1表示不做周期性检查,只在客户端获取连接时对闲置连接进行处理。 IdleTimeout: 5 * time.Minute, //闲置超时,默认5分钟,-1表示取消闲置超时检查 MaxConnAge: 600 * time.Second, //连接存活时长,从创建开始计时,超过指定时长则关闭连接,默认为0,即不关闭存活时长较长的连接 //命令执行失败时的重试策略 MaxRetries: 1, // 命令执行失败时,最多重试多少次,默认为0即不重试 MinRetryBackoff: 8 * time.Millisecond, //每次计算重试间隔时间的下限,默认8毫秒,-1表示取消间隔 MaxRetryBackoff: 512 * time.Millisecond, //每次计算重试间隔时间的上限,默认512毫秒,-1表示取消间隔 }) var ctx = context.Background() pong, err := RedisClient.Ping(ctx).Result() if err != nil { fmt.Println( "redis 连接失败:" , pong, err) log.Panicf( "redis connect failed: %v" , err) } return RedisClient } |
然后将任务写入redis
1 2 3 | if err := initialization.RedisClient.LPush(ctx, string(QueueName), string(queueValue)).Err(); err != nil { return err } |
然后启动一个异步监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | func ListenQueue(queueName string) { // 确保即使某个代码执行异常,整个程序不会panic中断 defer func () { err := recover() if err != nil { log.Println( "程序遭遇严重异常!!!!" ) ListenQueue(queueName) } }() for { ctx := initialization.NewTraceIDContext() // 每个业务启动创建一个trace_id values, err := initialization.RedisClient.BRPop(ctx, 5*time.Second, queueName).Result() // 设置一个5秒的超时时间 if err == redis.Nil { // 查询不到数据 time.Sleep(1 * time.Second) continue } if err != nil { // 查询出错,则每隔10秒重新查询 time.Sleep(10 * time.Second) continue } initialization.WithContext(ctx).Info( "消费到数据:" , values) if len(values) != 2 { initialization.WithContext(ctx).Errorf( "数据格式不正确,需要长度为2,但实际长度%d" , len(values)) continue } // TODO 消费操作,values是数组,但理论上values的默认长度是1 QueueExecute(ctx, queueName, values[1]) // 实际执行任务处理的方法 } } |
用这种方式,需要注意,超时时间要稍微长一些,因为超时时间短了,会触发重试,一旦重试可能会造成队列里面的数据丢失
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2017-06-26 xxx.app已损坏,打不开.你应该将它移到废纸篓-已解决