token-bucket-rate-limiter-clj
Clojure
(defn token-bucket
"Returns a stateful fn that takes one token per call, or false when empty."
[capacity refill-per-sec]
(let [state (atom {:tokens (double capacity) :last (System/nanoTime)})]
(fn []
(let [now (System/nanoTime)]
(-> (swap! state
(fn [{:keys [tokens last]}]
(let [elapsed (/ (- now last) 1e9)
tokens (min (double capacity)
(+ tokens (* elapsed refill-per-sec)))]
(if (>= tokens 1.0)
{:tokens (- tokens 1.0) :last now :ok true}
{:tokens tokens :last now :ok false}))))
:ok)))))