Coder Social home page Coder Social logo

ratelimit's Introduction

~ ratelimit ~

A simple token bucket based rate limiter.

     

go get github.com/zekroTJA/ratelimit

Intro

This package provides a verry simple, token bucket based rate limiter with the ability to return the status of the limiter on reserving a token.

Here you can read the docs of this package, generated by godoc.org.


Usage Example

In 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, for example:

// ...

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.


Copyright (c) 2019 zekro Development (Ringo Hoffmann).
Covered by MIT licence.

ratelimit's People

Contributors

zekrotja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.