ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Golang 请求限速、排队实现

2022-04-29 08:00:59  阅读:177  来源: 互联网

标签:queue err RequestParam 队列 排队 限速 Golang RequestQueue 请求


概要

 

在调用第三方 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

标签:queue,err,RequestParam,队列,排队,限速,Golang,RequestQueue,请求
来源: https://www.cnblogs.com/cheyunhua/p/16205287.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有