Liking cljdoc? Tell your friends :D

fr33m0nk/clj-bucket4j

clj-bucket4j is a a simple library that wraps over Bucket4J and offers convenience methods for easy implementation in Clojure code. For further documentation, do refer Bucket4J official docs.

Clojars Project

Usage

All functions are available through the fr33m0nk.clj-bucket4j namespace.

Add the following to your project dependencies:

  • CLI/deps.edn dependency information
net.clojars.fr33m0nk/clj-bucket4j {:mvn/version "0.1.4"}
  • Leningen/Boot
[net.clojars.fr33m0nk/clj-bucket4j "0.1.4"]
  • Maven
<dependency>
  <groupId>net.clojars.fr33m0nk</groupId>
  <artifactId>clj-bucket4j</artifactId>
  <version>0.1.4</version>
</dependency>
  • Gradle
implementation("net.clojars.fr33m0nk:clj-bucket4j:0.1.4")

Example usages

Require at the REPL with:

(require '[fr33m0nk.clj-bucket4j :as b4j])

as a limiter for rate-limiting of heavy work

Imagine that you have a thread-pool executor and you want to know what your threads are doing at the moment when thread-pool throws RejectedExecutionException. Printing stack traces of all threads in the JVM will be the best way to know where are all threads have stuck and why the thread pool is overflown. But acquiring stack traces is a very cost operation by itself, and you want to do it not often than 1 time per 10 minutes:

(import java.util.concurrent.Executors)
(import java.util.concurrent.RejectedExecutionException)
(import java.lang.management.ManagementFactory)
(import java.util.concurrent.TimeUnit)

;; define the limit 1 time per 10 minutes
(def simple-bandwidth (b4j/simple-bandwidth 1 6000000))

;; construct the bucket
(def bucket (-> (b4j/bucket-builder)
                (b4j/add-limit simple-bandwidth)
                (b4j/build)))

(def executor (Executors/newSingleThreadExecutor))

(try
  (->> (range 10)
       (mapv #(do
                ;; simulate Executor failure
                (when (> % 5)
                  (.shutdown executor)
                  (.awaitTermination executor 1 TimeUnit/MINUTES))
                (.execute executor ^Runnable (fn []
                                               (println "processing this " %)
                                               (Thread/sleep 1000)
                                               (println "I am done"))))))
  (catch RejectedExecutionException ex
    (when (b4j/try-consume bucket 1)
      (let [thread-info-list (.dumpAllThreads (ManagementFactory/getThreadMXBean) true true)]
        ;; Dummy log fn
        (log-somewhere thread-info-list)))
    (throw ex)))


as a throttler

Suppose you need to have a fresh exchange rate between dollars and euros. To get the rate you continuously poll the third-party provider, and by contract with the provider you should poll not often than 100 times per 1 minute, else provider will block your IP:

;; define the limit 100 times per 1 minute
(def simple-bandwidth (b4j/simple-bandwidth 100 60000))

;; construct the bucket
(def bucket (-> (b4j/bucket-builder)
                (b4j/add-limit simple-bandwidth)
                (b4j/build)))
                 
(def exchange-rates (atom 0.0))                 

;; do polling in infinite loop
(while true
  ;; Consume a token from the token bucket.
  ;; If a token is not available this function will block until the refill adds one to the bucket.
  (b4j/block-and-consume bucket 1)
  
  (swap! exchange-rate #(identity %2) (poll-exchange-rate)))
  

License

Copyright © 2023 Prashant Sinha

Distributed under the MIT License.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close