Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/zekroTJA/ratelimit
simple token bucket based rate limiter (e.g. for limiting HTTP API requests)
https://github.com/zekroTJA/ratelimit
go hacktoberfest library package ratelimit tokenbucket
Last synced: 3 months ago
JSON representation
simple token bucket based rate limiter (e.g. for limiting HTTP API requests)
- Host: GitHub
- URL: https://github.com/zekroTJA/ratelimit
- Owner: zekroTJA
- License: mit
- Created: 2019-03-20T15:39:40.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2022-08-22T11:58:59.000Z (about 2 years ago)
- Last Synced: 2024-06-20T15:01:15.984Z (5 months ago)
- Topics: go, hacktoberfest, library, package, ratelimit, tokenbucket
- Language: Go
- Homepage:
- Size: 26.4 KB
- Stars: 6
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-golang-repositories - ratelimit
README
---
go get github.com/zekroTJA/ratelimit
---
## Intro
This package provides a verry simple, [token bucket](https://en.wikipedia.org/wiki/Token_bucket) based rate limiter with the ability to return the status of the limiter on reserving a token.
[Here](https://godoc.org/github.com/zekroTJA/ratelimit) you can read the docs of this package, generated by godoc.org.
---
## Usage Example
In [examples/webserver](examples/webserver) you can find a simple HTTP REST API design limiting accesses with this rate limit package:
Taking a look on just these two functions in [webserver.go](examples/webserver/webserver.go), for example:
```go
// ...const (
limiterLimit = 10 * time.Second
limiterBurst = 3
)// ...
// checkLimit is a helper function checking
// the availability of a limiter for the connections
// address or creating it if not existing. Then,
// the availability of tokens will be checked
// to perform an action. This state will be returned
// as boolean.
func (ws *webServer) checkLimit(w http.ResponseWriter, r *http.Request) bool {
// Getting the address of the incomming connection.
// Because you will likely test this with a local connection,
// the local port number will be attached and differ on every
// request. So, we need to cut away everything behind the last
// ":", if existent.
addr := r.RemoteAddr
if strings.Contains(addr, ":") {
split := strings.Split(addr, ":")
addr = strings.Join(split[0:len(split)-1], ":")
}// Getting the limiter for the current connections address
// or create one if not existent.
limiter, ok := ws.limiters[addr]
if !ok {
limiter = ratelimit.NewLimiter(limiterLimit, limiterBurst)
ws.limiters[addr] = limiter
}// Reserve a token from the limiter.
a, res := limiter.Reserve()// Attach the reservation result to the three headers
// "X-RateLimit-Limit"
// - containing the absolute burst rate
// of the limiter,
// "X-RateLimit-Remaining"
// - the number of remaining tickets after
// the request
// "X-RateLimit-Reset"
// - the UnixNano timestamp until a new token
// will be generated (only if remaining == 0)
w.Header().Set("X-RateLimit-Limit", fmt.Sprintf("%d", res.Burst))
w.Header().Set("X-RateLimit-Remaining", fmt.Sprintf("%d", res.Remaining))
w.Header().Set("X-RateLimit-Reset", fmt.Sprintf("%d", res.Reset.UnixNano()))// Return the succeed status of
// the token request
return a
}// handlerTest is the handler for /api/test root
func (ws *webServer) handlerTest(w http.ResponseWriter, r *http.Request) {
// Check and consume a token from the limiter,
// if available. If succeed, return status 200,
// else status 429.
if ws.checkLimit(w, r) {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusTooManyRequests)
}
}
```Our limiter has a total token volume (= `burst`) of 3 tokens and a limit of 1 token per 10 seconds, which means, that every 10 seconds a new token will be added to the token bucket *(until the bucket has is "full")*.
So, if you send 4 HTTP GET requests in a time span of under 10 Seconds to `/api/test`, you will get following result:
```
///////////////////////////
// REQUEST #1* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Ratelimit-Limit: 3
< X-Ratelimit-Remaining: 2
< X-Ratelimit-Reset: 0
< Date: Thu, 21 Mar 2019 09:03:11 GMT
< Content-Length: 0
<///////////////////////////
// REQUEST #2* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Ratelimit-Limit: 3
< X-Ratelimit-Remaining: 1
< X-Ratelimit-Reset: 0
< Date: Thu, 21 Mar 2019 09:03:12 GMT
< Content-Length: 0
<///////////////////////////
// REQUEST #3* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Ratelimit-Limit: 3
< X-Ratelimit-Remaining: 0
< X-Ratelimit-Reset: 1553159004253249800
< Date: Thu, 21 Mar 2019 09:03:14 GMT
< Content-Length: 0
<///////////////////////////
// REQUEST #4* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 429 Too Many Requests
< X-Ratelimit-Limit: 3
< X-Ratelimit-Remaining: 0
< X-Ratelimit-Reset: 1553159004253249800
< Date: Thu, 21 Mar 2019 09:03:15 GMT
< Content-Length: 0
<
```As you can see, we are receiving status code `200 OK` exactly 3 times. Also, you can see that the ammount of remaining tokens is returned in a `X-Ratelimit-Remaining` header and also the time until a new token will be generated in the `X-Ratelimit-Reset` header *(as UnixNano timestamp)* when no tokens are remaining.
This concept ofreturning these information as headers were inspired by the design of the [REST API of discordapp.com](https://discordapp.com/developers/docs/topics/rate-limits).
---
Copyright (c) 2019 zekro Development (Ringo Hoffmann).
Covered by MIT licence.