我有一个API,我也在发布一个小JSON对象。
这是一个无限循环,循环超过7种颜色(彩虹)并将它们发送到上述JSON对象中。
我连接的API的速率限制为每分钟40个请求。
我不想达到限速,所以我设计了一种方法来避免这种情况;
它看起来像这样:
var rateLimit int
func main() {
request := gorequest.New().SetDebug(false)
// Set the initial request bucket to 40
rateLimit = 40
go topUpLimiter()
for {
makeTheLightsBlinkTheRainbow(request)
}
}
func topUpLimiter() {
for range time.Tick(60 * time.Second) {
rateLimit += 40
}
}
func makeTheLightsBlinkTheRainbow(request *gorequest.SuperAgent) {
colours := [7]string{"red", "orange", "yellow", "green", "blue", "purple", "pink"}
for _, colour := range colours {
if rateLimit > 0 {
response, _, _ := request.Post("http://example.com/blink").
Send(fmt.Sprintf(`{"color":"%v"}`, colour)).
End()
rateLimit--
} else {
time.Sleep(1 * time.Second)
}
}
}
这有效,而且我没有达到速率限制,但是一旦我用完了请求,循环就会继续运行,并且只有在rateLimit
变量充满时才会再次开始发出请求。
我正在使IoT灯闪烁彩虹的颜色,结果是一旦rateLimit
变量用完后颜色就会失序,然后由于for循环刚好加满了继续跑步。
我希望在等待rateLimit
变量补充时暂停/阻止for循环,以便颜色不会出现故障。
我将如何实现类似的东西?从我的搜索来看似乎可能有渠道,但我不太确定如何做到这一点。
这是最终发生的事情的一个例子:https://play.golang.org/p/r6OG4kK9vCP 一旦它完成运行,你会注意到打印出的颜色大约在中途发生故障。
答案 0 :(得分:1)
我的建议:采取完全不同的方法来限速。
我会把它放在HTTP传输中,因为逻辑上应该存在这样的限制,然后你根本不需要破坏你的应用程序代码。类似的东西:
import (
"net/http"
"golang.org/x/time/rate"
)
type rateLimitTransport struct {
limiter *rate.Limiter
xport http.RoundTripper
}
var _ http.RoundTripper = &rateLimitTransport{}
func newRateLimitTransport(r float64, xport http.RoundTripper) http.RoundTripper {
return &rateLimitTransport{
limiter: rate.NewLimiter(rate.Limit(r), 1),
xport: xport,
}
}
func (t *rateLimitTransport) RoundTrip(r *http.Request) (*http.Response, error) {
t.limiter.Wait(r.Context())
return t.xport.RoundTrip(r)
}
这使用golang.org/x/time/rate
包来实现速率限制。 newRateLimitTransport()
创建了一个新的速率限制传输,其中r
是每秒允许的最大请求数。
要利用此功能,请在HTTP客户端中为后端API使用速率限制传输的实例:
// set this in `init()` for example
myClient := http.&Client{
// Use a rate-limiting transport which falls back to the default
Transport: newRateLimitTransport(60, http.DefaultTransport)
}
// Then later use `myClient` instead of the default, when making API
// requests:
req, err := http.NewRequest(http.MethodPost, url, body)
if err != nil {
return err
}
myClient.Do(req)
答案 1 :(得分:0)
尝试更改为
func makeTheLightsBlinkTheRainbow(request *gorequest.SuperAgent) {
colours := [7]string{"red", "orange", "yellow", "green", "blue", "purple", "pink"}
i := 0
for {
if rateLimit > 0 {
response, _, _ := request.Post("http://example.com/blink").
Send(fmt.Sprintf(`{"color":"%v"}`, colours[i])).
End()
i = (i+1) % 7
rateLimit--
} else {
time.Sleep(1 * time.Second)
}
}
}