Skip to content

Instantly share code, notes, and snippets.

@leandrosilva
Created May 29, 2011 02:04
Show Gist options
  • Save leandrosilva/997393 to your computer and use it in GitHub Desktop.
Save leandrosilva/997393 to your computer and use it in GitHub Desktop.
Playing with Clojure, Redis, Compojure, and Jedis library
As always, I'm just playing with interesting things to relax a little bit. Just it.
== 1. Dependencies
I tried to use redis-clojure but it sucks and I shifted to Jedis which rocks. So if you want to try
as well, this little joke (ops! I mean...) program depends on:
* org.clojure/clojure "1.2.0"
* org.clojure/clojure-contrib "1.2.0"
* redis.clients/jedis "1.5.2"
* commons-pool/commons-pool "1.4"
I suggest use Leiningen to get these. ;)
== 2. Improvements
In this program, I'm playing with Redis set, list, and key-value to implement a primitive queue. But
y'know, it's not too idiomatic Clojure because I'm using a Java library directly. I think that It
can be improved a lot. If you try, let me know please.
== 3. Output
So if you run in a `lein repl` instance:
user=> (do (load-file "src/qdis/queue.clj") (qdis.queue/run-tests))
...you should see something like that:
::: running test functions :::
TEST 1 (enqueue 'padoca' 'panguan') = qdis:queue:padoca:uuid:272
TEST 2 (dequeue 'padocax') = :queue-not-found-or-is-empty
TEST 3 (dequeue 'padoca') = {:item-uuid qdis:queue:padoca:uuid:272, :item panguan}
TEST 4.1 (enqueue 'padoca' 'panguan1') = qdis:queue:padoca:uuid:273
TEST 4.2 (enqueue 'padoca' 'panguan2') = qdis:queue:padoca:uuid:274
TEST 4.3 (enqueue 'padoca' 'panguan3') = qdis:queue:padoca:uuid:275
TEST 4.4 (dequeue 'padoca') = {:item-uuid qdis:queue:padoca:uuid:273, :item panguan1}
TEST 4.5 (dequeue 'padoca') = {:item-uuid qdis:queue:padoca:uuid:274, :item panguan2}
TEST 4.6 (dequeue 'padoca') = {:item-uuid qdis:queue:padoca:uuid:275, :item panguan3}
:ok
(ns qdis.jedis
(:import [redis.clients.jedis Jedis JedisPool]))
;; use a jedis connection pool to be thread safe
(def ^{:private true} *jedis-pool* (ref nil))
(defn initialize-pool [redis-config]
(dosync
(ref-set *jedis-pool* (JedisPool. (:host redis-config) (:port redis-config)))))
(defn finalize-pool []
(.destroy @*jedis-pool*))
(defn connect []
(let [jedis (.getResource @*jedis-pool*)]
(.select jedis 0)
jedis))
(defn disconnect [jedis]
(.returnResource @*jedis-pool* jedis))
;; redis-like api
(def jedis)
(defmacro with-jedis [& exprs]
`(do
(binding [jedis (connect)]
(let [result# ~@exprs]
(disconnect jedis)
result#))))
(defn -set
([jedis* key value] (.set jedis* key value))
([key value] (-set jedis key value)))
(defn -get
([jedis* key] (.get jedis* key))
([key] (-get jedis key)))
(defn -del
([jedis* key] (.del jedis* (into-array [key])))
([key] (-del jedis key)))
(defn -sadd
([jedis* set-key value] (.sadd jedis* set-key value))
([set-key value] (.sadd jedis set-key value)))
(defn -incr
([jedis* key] (.incr jedis* key))
([key] (.incr jedis key)))
(defn -lpush
([jedis* list-key value] (.lpush jedis* list-key value))
([list-key value] (.lpush jedis list-key value)))
(defn -rpop
([jedis* list-key] (.rpop jedis* list-key))
([list-key] (.rpop jedis list-key)))
(ns qdis.queue
(:use qdis.jedis))
;; settings
(def ^{:private true} queue-set "qdis:queueset")
(def ^{:private true} queue-uuid "qdis:uuid")
(def ^{:private true} qdis-tag "qdis:")
(def ^{:private true} queue-tag "queue:")
(def ^{:private true} uuid-tag ":uuid:")
(defn- which-queue-name-for [queue]
(str qdis-tag queue-tag queue))
(defn- which-item-uuid-for [queue-name uuid]
(str queue-name uuid-tag uuid))
;; api
(defn enqueue [queue item]
(with-jedis
(do
(let [queue-name (which-queue-name-for queue)]
;; create the queue (if it doesn't exists)
(qdis.jedis/-sadd queue-set queue-name)
;; get a uuid to received item
(let [item-uuid (which-item-uuid-for queue-name (qdis.jedis/-incr queue-uuid))]
;; bind this uuid to item's value
(qdis.jedis/-set item-uuid item)
;; and finally push item's uuid to queue
(qdis.jedis/-lpush queue-name item-uuid)
item-uuid)))))
(defn dequeue [queue]
(with-jedis
(do
(let [result (let [queue-name (which-queue-name-for queue)]
;; get item's uuid from queue
(let [item-uuid (qdis.jedis/-rpop queue-name)]
(if (nil? item-uuid)
;; being nil, it means that this queue doesn't exists or is empty
:queue-not-found-or-is-empty
;; or since queue exists, get and del the item
(let [item (qdis.jedis/-get item-uuid)]
(qdis.jedis/-del item-uuid)
{:item-uuid item-uuid :item item}))))]
result))))
;; tests
(defn run-tests []
(qdis.jedis/initialize-pool {:host "127.0.0.1" :port 6379})
(println "\n::: running test functions :::\n")
(println "TEST 1 (enqueue 'padoca' 'panguan') =" (enqueue "padoca" "panguan"))
(println "TEST 2 (dequeue 'padocax') =" (dequeue "padocax"))
(println "TEST 3 (dequeue 'padoca') =" (dequeue "padoca"))
(println)
(println "TEST 4.1 (enqueue 'padoca' 'panguan1') =" (enqueue "padoca" "panguan1"))
(println "TEST 4.2 (enqueue 'padoca' 'panguan2') =" (enqueue "padoca" "panguan2"))
(println "TEST 4.3 (enqueue 'padoca' 'panguan3') =" (enqueue "padoca" "panguan3"))
(println "TEST 4.4 (dequeue 'padoca') =" (dequeue "padoca"))
(println "TEST 4.5 (dequeue 'padoca') =" (dequeue "padoca"))
(println "TEST 4.6 (dequeue 'padoca') =" (dequeue "padoca"))
(println)
(qdis.jedis/finalize-pool)
:ok)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment