Distributed Bucket4J implementation for Datomic Database
Note: this library uses Clojure wrapper for Bucket4J, clj-bucket4j
Add the following to your project dependencies:
- CLI/deps.edn dependency information
net.clojars.fr33m0nk/clj-bucket4j-datomic {:mvn/version "0.1.4"}
- Leningen/Boot
[net.clojars.fr33m0nk/clj-bucket4j-datomic "0.1.4"]
- Maven
<dependency>
<groupId>net.clojars.fr33m0nk</groupId>
<artifactId>clj-bucket4j-datomic</artifactId>
<version>0.1.4</version>
</dependency>- Gradle
implementation("net.clojars.fr33m0nk:clj-bucket4j-datomic:0.1.4")Add Datomic peer dependency in you project if not present.
Prior to using below functions, it is necessary to execute these Datomic migrations
All functions are available through the fr33m0nk.clj-bucket4j-datomic namespace
| Name | Description |
|---|---|
fr33m0nk.clj-bucket4j-datomic/->datomic-proxy-manager |
Returns Distributed Bucket4J Proxy Manager for Datomic |
fr33m0nk.clj-bucket4j-datomic/add-distributed-bucket |
Adds a distributed bucket to Datomic. NOOP if bucket already exists. Returns the instance of bucket |
fr33m0nk.clj-bucket4j-datomic/remove-distributed-bucket |
Removes a distributed bucket. Permanent removal is determined by the RecoveryStrategy chosen while creating the bucket. Default strategy is to always RestoreOnDelete |
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:
(require '[datomic.api :as d]
'[fr33m0nk.datomic-schema :refer [b4j-schema]]
'[fr33m0nk.clj-bucket4j-datomic :as b4j-datomic])
(import '(io.github.bucket4j.distributed.proxy ClientSideConfig))
(def datomic-conn (return-datomic-connection))
;; Execute Datomic migrations for supporting Distributed Bucket4J
@(d/transact datomic-conn b4j-schema)
;; Instance of datomic-proxy-manager
;; For most cases `(ClientSideConfig/getDefault)` is enough
;; Look into documentation of ClientSideConfig to figure right scenarios to customize it
(def datomic-proxy-manager (b4j-datomic/->datomic-proxy-manager datomic-conn (ClientSideConfig/getDefault)))
;; Bucket configuration allowing 100 hits in 60000 ms (1 minute)
(def bucket-configuration (-> (BucketConfiguration/builder)
(.addLimit
(reify java.util.function.Function
(apply [_ limit]
(.capacity limit capacity)
(.refillGreedy limit capacity (Duration/ofMillis interval-ms)))))
(.build)))
;; Adds a distributed bucket to Datomic
(def distributed-bucket (b4j-datomic/add-distributed-bucket datomic-proxy-manager "test-bucket-1" bucket-configuration))
(def exchange-rates (atom 0.0))
;; do polling in infinite loop
(while true
;; Consume a token from the token bucket.
;; Depending on the availability of Token, `.tryConsume` returns true or false.
(when (.tryConsume distributed-bucket 1)
(swap! exchange-rate #(identity %2) (poll-exchange-rate))))
More detailed usages of above functions and more can be found in tests.
Copyright © 2026 Prashant Sinha
Distributed under the MIT License.