Skip to content

Instantly share code, notes, and snippets.

@chmike
Created December 18, 2023 15:31
Show Gist options
  • Save chmike/a85c77cd4725ce052a6cb10d6381655c to your computer and use it in GitHub Desktop.
Save chmike/a85c77cd4725ce052a6cb10d6381655c to your computer and use it in GitHub Desktop.

Revisions

  1. chmike created this gist Dec 18, 2023.
    43 changes: 43 additions & 0 deletions simpleRateLimiter.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    // NewRateLimiter returns a rate limiter function returning false
    // when the event must be rejected, and true when it must be accepted.
    // The rate is expressed in Hz (events/seconds). It simply ensures that
    // the time interval between two accept satisfies the rate criteria. It
    // is equivalent to the token bucket algorithm with a bucket size of one.
    func NewRateLimiter(rate float64) func() bool {
    var stamp time.Time // time stamp of last accepted event
    return func() bool {
    now := time.Now()
    if now.Sub(stamp).Seconds() *rate < 1. {
    return false
    }
    stamp = now
    return true
    }
    }

    // The following is a usage example with a rate limiting middelware.
    func rateLimiter(rate float64, f http.HandlerFunc) http.HandlerFunc {
    rl := NewRateLimiter(rate)
    return func(w http.ResponseWriter, r *http.Request) {
    if !rl() {
    http.Error(w, "too many requests, retry later", http.StatusTooManyRequests)
    return
    }
    f(w, r)
    }
    }

    // some example server action
    func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "hello !")
    }

    func main() {
    http.HandleFunc("/", rateLimiter(1, hello)) // accept at most one request per second
    http.ListenAndServe(":8080", nil)
    }