• Golang 请求限速、排队实现


    概要

     

    在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP 429(Too Many Requests) 然后就会有一段时间的禁止访问.

    为了应对这种限速的情况, 通过一个简单的请求队列来控制访问的速度, 之后基本没遇到过 HTTP 429 了.

    实现思路

     

    首先, 每个请求包装成一个 RequestParam 的 struct, 其中包含请求的地址,类型,参数以及 response 的 channel.

    发送请求的时候, 只要将 RequestParam 放入请求队列中即可, 请求完成后, 将 response 放入对应的 channel 中.

    整个代码实现很简单:

      package util
       import (
         "fmt"
       
         apiclient "gitee.com/wangyubin/gutils/api_client"
        "gitee.com/wangyubin/gutils/logger"
      )
      // request 包含的内容
      type RequestParam struct {
        Api     string
        Method  string
        JsonReq interface{}
        Resp    chan []byte
      }
     // 请求队列, 本质是一个channel
      type RequestQueue struct {
        Queue chan RequestParam
      }
      var queue *RequestQueue
      // 获取队列
      func GetQueue() *RequestQueue {
        return queue
      }
      // 初始化队列
      func InitRequestQueue(size int) {
        queue = &RequestQueue{
          Queue: make(chan RequestParam, size),
        }
      }

      // 将请求放入队列
      func (rq *RequestQueue) Enqueue(p RequestParam) {
        rq.Queue <- p
     }

      // 请求队列服务, 一直等待接受和处理请求
      func (rq *RequestQueue) Run() {
        lg := logger.GetLogger()
        for p := range rq.Queue {
          var resp []byte
          var err error
          switch p.Method {
          case "GET":
            resp, err = apiclient.GetJson(p.Api, p.JsonReq)
          case "POST":
            resp, err = apiclient.PostJson(p.Api, p.JsonReq)
          default:
            err = fmt.Errorf("Wrong type of METHOD(%s)\n", p.Method)
         }
          if err != nil {
            lg.Err(err).Msg("access api error: " + p.Api)
           continue
          }
          if p.Resp != nil {
           p.Resp <- resp
           close(p.Resp)
          }

        }
        lg.Info().Msg("request queue finished!")
      }

    这里的请求是用了我自己封装的 apiclient, 可以根据实际情况替换.

    在我的应用场景里, 只要 api 顺序访问就不会出现 HTTP 429 了, 如果这样觉得速度太快的的话, 可以尝试在 Run() 函数中加入一些时间间隔.

      func (rq *RequestQueue) Run() {
        lg := logger.GetLogger()
        for p := range rq.Queue {
           time.Sleep(1 * time.Second)
           // ... 省略的代码 ...
        }
      
        lg.Info().Msg("request queue finished!")
      }

    使用方法

     

    使用很简单, 首先启动, 然后每个调用的地方将 RequestParam 放入队列并等待 response 即可.

    启动队列服务

     func main() {
          // init request queue and start queue service
     util.InitRequestQueue(100)
          queue := util.GetQueue()
          defer close(queue.Queue)
          go queue.Run()
      
          // 其他启动代码
      }

    使用队列服务

      func Request(param1 string, param2 int) error {
        api := "http://xxxx.com"
        api = fmt.Sprintf("%s?period=%s&size=%d", api, param1, param2)
       
        queue := util.GetQueue()
        param := util.RequestParam{
          Api:    api,
          Method: "GET",
          Resp:   make(chan []byte, 1),
       }
       queue.Enqueue(param)
      
       var respData struct {
         Status string       `json:"status"`
         Data   []model.Data `json:"data"`
       }
       var err error
       for resp := range param.Resp {
         err = json.Unmarshal(resp, &respData)
         if err != nil {
           lg.Err(err).Msg("unmarshal json error")
           return err
         }
       }
      
       fmt.Println(respData) 
       return  err
      }

    链接:https://www.cnblogs.com/wang_yb/p/13018901.html

  • 相关阅读:
    wzplayer,tlplayer正式支持扩展dlna协议
    ASP.NET导出Excel或Word文件格式
    .NET对象序列化:TimeSpan
    探讨.NET中的联合结构
    浅析ASP.NET应用Autofac获取页面服务
    ASP.NET封装JS文件到DLL中并在页面中调用
    MySQL和MongoDB设计实例对比
    .NET中的异步编程:使用F#简化异步编程
    ASP.NET MVC 2自定义验证
    ASP.NET Session丢失问题原因及解决方案
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/16205287.html
Copyright © 2020-2023  润新知