An opinionated Clojure library wrapping Aerospike Java Client.
- Java 8
- Clojure 1.8
- Converts Java client's callback model into a future (manifold/deferred) based API.
- Expose passing functional transcoders over payloads (both put/get).
- Health-check utility.
- Functions return Clojure records.
- Non blocking only: Expose only the non-blocking API. Block with
deref
if you like. - Futures instead of callbacks. Futures (and functional chaining) are more composable and less cluttered.
If a synchronous behaviour is still desired, the calling code can still deref (
@
) the returned future object. For a more sophisticated coordination, a variety of control mechanism is supplied by manifold/deferred, or via the library using transcoders or hooks. - Follows the method names of the underlying Java APIs.
- TTLs should be explicit, and developers should think about them. Forces passing a ttl and not use the cluster default.
- Minimal dependencies.
- Single client per Aerospike namespace.
- Currently supports only single bin records.
- Does not expose batch/scan operations. Batch reads/writes are supported via
get-multiple
/put-multiple
.
- Support batch asynchronous APIs.
user=> (require '[aerospike-clj.client :as aero])
nil
user=> (def c (aero/init-simple-aerospike-client
#_=> ["aerospike-001.com", "aerospik-002.com"] "my-ns" {:enable-logging true}))
It is possible to inject additional asynchronous user-defined behaviour. To do that add an instance of ClientEvents
. Some useful info is passed in in-order to support metering and to read client configuration. op-start-time
is (System/nanoTime)
more here.
(let [c (aero/init-simple-aerospike-client
["localhost"]
"test"
{:client-events (reify ClientEvents
(on-success [_ op-name op-result index op-start-time db]
(when (:enable-logging? db)
(println op-name "success!")))
(on-failure [_ op-name op-ex index op-start-time db]
(println "oh-no" op-name "failed on index" index)))})]
(get-single c "index" "set-name"))
For demo purposes we will use a docker based local DB:
$ sudo docker run -d --name aerospike -p 3000:3000 -p 3001:3001 -p 3002:3002 -p 3003:3003 aerospike
And connect to it:
user=> (def c (aero/init-simple-aerospike-client ["localhost"] "test"))
#'user/db
user=> (require '[manifold.deferred :as d])
nil
user=> (aero/put c "index" "set-name" 42 1000)
<< … >>
user=> (def f (aero/get-single c "index" "set-name"))
#'user/f
user=> (d/chain (aero/get-single c "index" "set-name")
#_=> :ttl
#_=> aero/expiry-unix
#_=> #(java.time.Instant/ofEpochSecond %)
#_=> str
#_=> println)
<< … >>
2019-01-10T09:02:45Z
We actually get back a record with the payload, the DB generation and the ttl (in an Aerospike style EPOCH format).
user=> @(aero/get-single c "index" "set-name")
#aerospike_clj.client.AerospikeRecord{:payload 42, :gen 1, :ttl 285167713}
Aerospike returns a TTL on the queried records that is Epoch style, but with a different "beginning of time" which is "2010-01-01T00:00:00Z". Call expiry-unix
with the returned TTL to get a UNIX TTL if you want to convert it later to a more standard timestamp.
Testing is performed against a local Aerospike running in the latest docker
$ sudo docker run -d --name aerospike -p 3000:3000 -p 3001:3001 -p 3002:3002 -p 3003:3003 aerospike
$ lein test
PRs are welcome!
Distributed under the Apache 2.0 License - found here.