func BuildThrottleMiddleWare(interval int, keyfunc Keyfunc) func(c *web.C, h http.Handler) http.Handler {
	var redisThrottleScript = redigo.NewScript(
		1,
		fmt.Sprintf(
			`local current; current = redis.call('incr',KEYS[1]);if tonumber(current) == 1 then redis.call('expire', KEYS[1], %d) end return {current, redis.call('ttl', KEYS[1])}`,
			interval,
		),
	)
	return func(c *web.C, h http.Handler) http.Handler {
		handler := func(w http.ResponseWriter, r *http.Request) {
			throttleKey, limit := keyfunc(c, r)
			if limit > 0 {
				redis_conn := c.Env["redis"].(redigo.Conn)
				rsp, err := redigo.Values(redisThrottleScript.Do(redis_conn, throttleKey))
				if err != nil {
					log.Printf("Throttling: Cache failure, %v", err)
					http.Error(w, fmt.Sprintf("Throttling: Cache failure, %v", err), http.StatusServiceUnavailable)
				}
				numRequests := int(rsp[0].(int64))
				ttl := rsp[1].(int64)
				h := w.Header()
				setHeaderInt(h, "X-RateLimit-Limit", limit)
				setHeaderInt(h, "X-RateLimit-Remaining", limit-numRequests)
				setHeaderInt64(h, "X-Ratelimit-Reset", time.Now().Unix()+ttl)
				if numRequests > limit {
					http.Error(w, fmt.Sprintf("Request rate limit exceeded - allowed rate is %d requests every %d seconds", limit, interval), 429)
					return
				}
			}
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(handler)
	}
}
/*
Throttling middleware using redis.

Parameters

interval - throttling interval in seconds
keyfunc - function that looks at the current request and returns an appropriate throttle key and limit

Assumes redis connection is in c.Env["redis"] - see BuildRedis()


Example

m := web.New()
m.Use(middleware.EnvInit)
m.Use(redis.BuildRedis(config.RedisAddr))
m.Use(IdentifyServiceMiddleware)
m.Use(redis.BuildThrottleMiddleWare(3600, func(c *web.C, r *http.Request) (string, int) {
service_id := c.Env["service_id"].(int)
return fmt.Sprintf("api:throttle:%d", service_id), 1000
}))
package redis
import (
	"fmt"
	"log"
	"net/http"
	"strconv"
	"time"
	redigo "github.com/garyburd/redigo/redis"
	"github.com/zenazn/goji/web"
)
type Keyfunc func(c *web.C, r *http.Request) (string, int)