// RateLimit creates a throttler that limits the number of requests allowed // in a certain time window defined by the Quota q. The q parameter specifies // the requests per time window, and it is silently set to at least 1 request // and at least a 1 second window if it is less than that. The time window // starts when the first request is made outside an existing window. Fractions // of seconds are not supported, they are truncated. // // The vary parameter indicates what criteria should be used to group requests // for which the limit must be applied (ex.: rate limit based on the remote address). // See varyby.go for the various options. // // The specified store is used to keep track of the request count and the // time remaining in the window. The throttled package comes with some stores // in the throttled/store package. Custom stores can be created too, by implementing // the Store interface. // // Requests that bust the rate limit are denied access and go through the denied handler, // which may be specified on the Throttler and that defaults to the package-global // variable DefaultDeniedHandler. func RateLimit(q throttled.Quota, methods []string, vary *throttled.VaryBy, store throttled.Store) *throttled.Throttler { // Extract requests and window reqs, win := q.Quota() // Create and return the throttler return throttled.Custom(&rateLimiter{ reqs: reqs, window: win, vary: vary, store: store, methods: methods, }) }
func main() { flag.Parse() var h http.Handler var ok, ko int var mu sync.Mutex // Keep the start time to print since-time start := time.Now() // Create the custom throttler using our custom limiter t := throttled.Custom(&customLimiter{}) // Set its denied handler t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if *output == "v" || *output == "ko" { log.Printf("KO: %s", time.Since(start)) } throttled.DefaultDeniedHandler.ServeHTTP(w, r) mu.Lock() defer mu.Unlock() ko++ }) // Throttle the OK handler rand.Seed(time.Now().Unix()) h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if *output == "v" || *output == "ok" { log.Printf("ok: %s", time.Since(start)) } if *delayRes > 0 { wait := time.Duration(rand.Intn(int(*delayRes))) time.Sleep(wait) } w.WriteHeader(200) mu.Lock() defer mu.Unlock() ok++ })) // Print stats once in a while go func() { for _ = range time.Tick(10 * time.Second) { mu.Lock() log.Printf("ok: %d, ko: %d", ok, ko) mu.Unlock() } }() fmt.Println("server listening on port 9000") http.ListenAndServe(":9000", h) }