revamp rate limiter

This commit is contained in:
Mukhtar Akere
2025-04-29 23:41:03 +01:00
parent c0703cb622
commit 1248d99680
3 changed files with 23 additions and 18 deletions

3
go.mod
View File

@@ -9,6 +9,7 @@ require (
github.com/beevik/etree v1.5.0
github.com/cavaliergopher/grab/v3 v3.0.1
github.com/go-chi/chi/v5 v5.1.0
github.com/go-co-op/gocron/v2 v2.16.1
github.com/goccy/go-json v0.10.5
github.com/google/uuid v1.6.0
github.com/gorilla/sessions v1.4.0
@@ -26,7 +27,6 @@ require (
github.com/anacrolix/missinggo/v2 v2.7.3 // indirect
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-co-op/gocron/v2 v2.16.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
@@ -36,6 +36,5 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/stretchr/testify v1.10.0 // indirect
golang.org/x/sys v0.30.0 // indirect
)

2
go.sum
View File

@@ -220,6 +220,8 @@ github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPy
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=

View File

@@ -17,7 +17,6 @@ import (
"net"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"sync"
@@ -340,29 +339,34 @@ func New(options ...ClientOption) *Client {
}
func ParseRateLimit(rateStr string) *rate.Limiter {
if rateStr == "" {
return nil
}
re := regexp.MustCompile(`(\d+)/(minute|second)`)
matches := re.FindStringSubmatch(rateStr)
if len(matches) != 3 {
parts := strings.SplitN(rateStr, "/", 2)
if len(parts) != 2 {
return nil
}
count, err := strconv.Atoi(matches[1])
if err != nil {
// parse count
count, err := strconv.Atoi(strings.TrimSpace(parts[0]))
if err != nil || count <= 0 {
return nil
}
unit := matches[2]
// normalize unit
unit := strings.ToLower(strings.TrimSpace(parts[1]))
unit = strings.TrimSuffix(unit, "s")
burstSize := int(math.Ceil(float64(count) * 0.1))
if burstSize < 1 {
burstSize = 1
}
if burstSize > count {
burstSize = count
}
switch unit {
case "minute":
reqsPerSecond := float64(count) / 60.0
burstSize := int(math.Max(30, float64(count)*0.25))
return rate.NewLimiter(rate.Limit(reqsPerSecond), burstSize)
case "second":
burstSize := int(math.Max(30, float64(count)*5))
case "minute", "min":
return rate.NewLimiter(rate.Limit(float64(count)/60.0), burstSize)
case "second", "sec":
return rate.NewLimiter(rate.Limit(float64(count)), burstSize)
case "hour", "hr":
return rate.NewLimiter(rate.Limit(float64(count)/3600.0), burstSize)
default:
return nil
}