延时队列 golang 订单消费

416 阅读1分钟

1 、语言自带函数方法 比如jdk的DelayQueue

这里就不做讨论了,无法做持久化

2、定时任务扫表。

效力低,增大数据库压力,这里也不讨论

3、rabbitmq 死信队列,不过要下插件,否者他是按顺序的,会阻塞。

4、 Redis sorted set

我们用的这种:

  • 先把未支付订单存在redis的zset中
  • 支付成功的,去redis利查,然后更改订单状态
  • 30分钟未支付,通过判断zset中的key,可以判断订单是佛有超过30分钟,另外做处理
import (
   "github.com/gomodule/redigo/redis"
   "time"
)
// InsertOrder
// @description: 插入订单
// @return error
// @2022-11-09 09:44:20

const TimeInterval int64 = 1800
func (rs *RedisUtil) InsertOrder(OrderUuid string) error {
   //  订单生成半个钟

   currentNSecond := time.Now().Unix()
   _, err := rs.client.Do("ZADD", "order", "INCR", currentNSecond+TimeInterval, OrderUuid)
   if err != nil {
      return err
   }
   return nil
}

// Unpaid
// @description: 查询半个钟未支付的,  查出来再删除
// @return error   value 是 sco
// @2022-11-09 09:45:35
func (rs *RedisUtil) Unpaid() error {
   var e error
   var count interface{}
   count, e = rs.client.Do("zcount", "order", 0, time.Now().Unix())
   if e != nil {
      return e
   }

   midCount := count.(int64)

   orderMap, err := redis.StringMap(rs.client.Do("ZRANGE", "order", 0, midCount, "withscores"))
   if err != nil {
      return err
   }
   for key := range orderMap {
      //删除redis 里面的数据
      // todo 更改订单状态
      _, _ = rs.client.Do("zrem", "order", key)
   }
   return nil
}

// PaymentCompleted
// @description: 支付完成,删除
// @return error
// @2022-11-09 09:46:05
func (rs *RedisUtil) PaymentCompleted(OrderUuid string) error {
   //1、首先查出来有没有这个订单2、更改订单状态,3、删除redis数据

   val, err := rs.client.Do("zrank", "order", OrderUuid)
   if err != nil {
      return err
   }

   if val != nil {
      // todo 更改订单状态

      _, err = rs.client.Do("zrem", "order", OrderUuid)
      if err != nil {
         return err
      }

   }

   return nil
}

5、 Redis 过期回调

无Ack 会延迟

6、时间轮

会有时间粒度问题,如果对粒度要求不大,可以使用