Skip to content

Commit

Permalink
Released 0.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
killme2008 committed Mar 23, 2016
1 parent 269d536 commit c335b9a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 43 deletions.
18 changes: 9 additions & 9 deletions README.md
Expand Up @@ -9,7 +9,7 @@ It's transformed from [rolling-rate-limiter](https://github.com/classdojo/rollin
Leiningen:

```clj
[clj-rate-limiter "0.1.3"]
[clj-rate-limiter "0.1.5"]
```

### Basic
Expand All @@ -20,12 +20,12 @@ Create an in-memory rate limiter with maximum 100 requsts in 1 seconds:
(require '[clj-rate-limiter.core :as r])
(def limiter (r/create
(r/rate-limiter-factory :memory
:interval 1000
:interval 1000
:max-in-interval 100)))
(println (r/allow? limiter "key1"))
(println (r/allow? limiter "key2"))
(count (filter true? (repeatedly 1000 #(r/allow? limiter "key3")))) ;;should be 100

(println (r/allow? limiter "key1"))
(println (r/allow? limiter "key2"))
(count (filter true? (repeatedly 1000 #(r/allow? limiter "key3")))) ;;should be 100
```

The `:interval` sets the time window unit in millseconds, and `:max-in-interval` sets the maximum requests in a time window, and `:memory` make the rate limiter store requests in memory.
Expand All @@ -34,13 +34,13 @@ After the limiter is created, you can use `(allow? limiter key)` to test if the
In a cluster, you may want to created a redis-backed limiter:

```clj
;;redis spec and pool as decribed in
;;redis spec and pool as decribed in
;;https://github.com/ptaoussanis/carmine
(def redis {:spec {:host "localhost" :port 6379 :timeout 5000}
:pool {:max-active (* 3 (.availableProcessors (Runtime/getRuntime)))
:min-idle (.availableProcessors (Runtime/getRuntime))
:max-wait 5000}})

(def limiter (r/create
(r/rate-limiter-factory :redis
:redis redis
Expand All @@ -62,7 +62,7 @@ You can set the minimum time in millseconds between requests by `:min-difference
:redis redis
:namespace "APIs"
:interval 1000
:min-difference 1
:min-difference 1
:max-in-interval 100)))
```

Expand Down
2 changes: 1 addition & 1 deletion project.clj
@@ -1,4 +1,4 @@
(defproject clj-rate-limiter "0.1.4"
(defproject clj-rate-limiter "0.1.5"
:description "Rate limiter for clojure that supports a rolling window, either in-memory or backed by redis"
:url "https://github.com/killme2008/clj-rate-limiter"
:license {:name "Eclipse Public License"
Expand Down
79 changes: 46 additions & 33 deletions src/clj_rate_limiter/core.clj
Expand Up @@ -187,13 +187,13 @@
(remove-permit [_ id ts]
(let [id (or id "")
key (format "%s-%s" namespace id)
before (- ts (mills->nanos interval))]
(when ts
before (- (System/nanoTime) (mills->nanos interval))]
(when (and ts (pos? ts))
(car/wcar {:spec redis
:pool pool}
(car/multi)
(car/zrem key ts)
(car/zremrangebyscore key 0 before)
(car/zremrangebyscore (release-key key) 0 before)
(car/zadd (release-key key) ts ts)
(car/expire (release-key key)
(long (Math/ceil (/ interval 1000))))
Expand All @@ -216,33 +216,46 @@

(comment
(defn- benchmark []
(let [rf (rate-limiter-factory :redis
:redis {:spec {:host "localhost" :port 6379 :timeout 5000}
:pool {:max-active (* 3 (.availableProcessors (Runtime/getRuntime)))
:min-idle (.availableProcessors (Runtime/getRuntime))
:max-wait 5000}}
:flood-threshold 10
:interval 1000
:max-in-interval 1000)
r (create rf)
cost (atom {:sum 0 :times 0})
ts 100
cl (java.util.concurrent.CountDownLatch. ts)]
(time
(do
(dotimes [n ts]
(->
(fn []
(dotimes [m 10000]
(let [{:keys [ts result total current]} (permit? r (mod m 20))]
(when (> total current)
(swap! cost (fn [{:keys [sum times]} s]
{:sum (+ sum s)
:times (inc times)})
(- total current)))
(remove-permit r (mod m 20) ts)))
(.countDown cl))
(Thread.)
(.start)))
(.await cl)
(println @cost))))))
(let [rf (rate-limiter-factory :redis
:redis {:spec {:host "localhost" :port 6379 :timeout 5000}
:pool {:max-active (* 3 (.availableProcessors (Runtime/getRuntime)))
:min-idle (.availableProcessors (Runtime/getRuntime))
:max-wait 5000}}
:flood-threshold 10
:interval 1000
:max-in-interval 100000)
r (create rf)
cost (atom {:total 0
:current 0
:max_total 0
:max_concurrent 0
:times 0})
ts 100
cl (java.util.concurrent.CountDownLatch. ts)]
(time
(do
(dotimes [n ts]
(->
(fn []
(dotimes [m 10000]
(let [{:keys [ts result total current]} (permit? r (mod m 1))]
(when result
(swap! cost (fn [{:keys [total current
times max_total max_concurrent]} t c]
{:total (+ total t)
:current (+ current c)
:max_total (if (< max_total t)
t
max_total)
:max_concurrent (if (< max_concurrent c)
c
max_concurrent)
:times (inc times)})
total
current))
(remove-permit r (mod m 1) ts)))
(.countDown cl))
(Thread.)
(.start)))
(.await cl)
(println @cost))))))

0 comments on commit c335b9a

Please sign in to comment.