golang API请求队列的实现
作者:wang_yb 发布时间:2024-03-11 16:39:50
标签:golang,API,请求队列
概要
在调用第三方 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
0
投稿
猜你喜欢
- zipfile模块是python中一个处理压缩文件的模块,解决了不少我们平常需要处理压缩文件的需求。大家还知道Python zipfile
- 本文实例为大家分享了利用opencv实现SIFT特征提取与匹配的具体代码,供大家参考,具体内容如下1、SIFT1.1、sift的定义SIFT
- 编解码器在字符与字节之间的转换过程称为编解码,Python自带了超过100种编解码器,比如:ascii(英文体系)gb2312(中文体系)u
- python 连接数据库操作, 方法如下:在本机的mysql 数据库中有一个名为yao的库,其中有一个名为user的表,表中的内容如图下面,
- 细节汇总函数的形参列表可以是多个,返回值列表也可以是多个形参列表和返回值列表的数据类型,可以是值类型、也可以是引用类型函数的命名遵循标识符命
- 1、搭载QT环境按win+R输入 pip install pyqt5 下载QT5 当然也可以去Qt的官网的下载 ,使用命令行更快捷方便 所以
- 问题描述:想要去掉图像背景,只保留中心部分目标:1.利用ITK-SNAP制作二值化标签(即mask)2.利用软件ITK-SNAP把一幅图像中
- 一个简单的PHP循环一维数组的实例,先是把字符串按照一定的规则进行转换成为数组,然后再进行遍历输出,实际是一个很简单的方法,因为最近做的一个
- 我就废话不多说了,大家还是直接看代码吧~func main() { var a chan string a =mak
- 对很多从事产品工作的同事来说,“以用户为中心”是工作的重点,同时也是难点。用户的心思难以捉摸,用户研究的工作也似乎高深莫测。不过,用户研究并
- import siximport timeit#查找任何特定代码执行的确切时间from ecdsa.curves import curves
- 如何修改程序默认时区由于系统安装时时区可能选择不对,并不是中国的东八区,导致依赖于日期时间函数无法正常使用找到一个比较简单的方法程序启动时加
- 1 sample(序列a,n)sample(序列a,n)功能:从序列a中随机抽取n个元素,并将n个元素生以list形式返回。例:from r
- 最近跟着OpenCV2-Python-Tutorials在学习python_opencv中直方图的反向投影时,第一种方法是使用numpy实现
- 用户登录验证脚本,Chkpwd.asp<% '=======用户登录验证脚本======= '
- 删除Git缓存的用户名和密码昨天在上传代码的时候提示输入用户名密码,结果输错了3次就没有提示框了,就一直报错(身份验证失败),没办法提交代。
- 如果需要对列表中的每个元素执行相同操作,这时就需要遍历列表的所有元素。books=['半生缘','往事并不如烟
- 在ASP中,FSO的意思是File System Object,即文件系统对象。
- 方法一 declare @max integer,@id integer declare cur_r
- 1.数组上的迭代NumPy 包含一个迭代器对象numpy.nditer。它是一个有效的多维迭代器对象,可以用于在数组上进行迭代。数组的每个元