Created
February 4, 2014 15:56
-
-
Save julienfantin/8806365 to your computer and use it in GitHub Desktop.
Carmine caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns beta-api.utils.cache | |
| (:require [taoensso.carmine :as car] | |
| [clj-time.coerce :as tc] | |
| [clj-time.core :as time])) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Redis | |
| (def conn-spec {:host "127.0.0.1" | |
| :port 6379 | |
| :timeout 8000}) | |
| (def redis-conn {:pool {} | |
| :spec conn-spec}) | |
| (defmacro wcar* [& body] `(car/wcar redis-conn ~@body)) | |
| (defn now [] (java.util.Date.)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Entries | |
| ;; Note, I'd rather have a deftype here, but nippy only handles basic | |
| ;; datatypes, though it has an extension feature, it seems very alpha... | |
| (defn value->entry [x] | |
| {:value x | |
| :created-at (now)}) | |
| (defn entry->value [e] | |
| (:value e)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Keys to ids | |
| (def root-key "cache-") | |
| (defn ensure-seq [x] | |
| (when x (if (coll? x) x (list x)))) | |
| (defn key->str [x] | |
| (cond (string? x) x | |
| (keyword? x) (name x) | |
| :else (str x))) | |
| (defn key->id [x] | |
| (->> x | |
| ensure-seq | |
| (map key->str) | |
| (clojure.string/join "_") | |
| (str root-key))) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Policies | |
| (defprotocol CachePolicy | |
| "Returns the number of seconds until expiration." | |
| (expiration [this])) | |
| (defn until-date [^java.util.Date date] | |
| "Returns a CachePolicy that will expire after the given date." | |
| (reify CachePolicy | |
| (expiration [_] | |
| (time/in-seconds | |
| (time/interval (tc/to-date-time (now)) | |
| (tc/to-date-time date)))))) | |
| (defn for-period [period t] | |
| "Returns a CachePolicy that will be valid for the given clj-time | |
| PeriodType." | |
| (reify CachePolicy | |
| (expiration [_] | |
| (time/in-seconds | |
| (time/interval (tc/to-date-time (now)) | |
| (tc/to-date-time (time/plus (tc/to-date-time (now)) | |
| (period t)))))))) | |
| (defn for-minutes [^Integer minutes] | |
| (for-period time/minutes minutes)) | |
| (defn for-seconds [^Integer seconds] | |
| (for-period time/seconds seconds)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Cache accessors | |
| (defn cache-get [^clojure.lang.Named key policy] | |
| (when-let [entry (wcar* (car/get (key->id key)))] | |
| (entry->value entry))) | |
| (defn cache-set [^clojure.lang.Named key policy value] | |
| (when-let [id (key->id key)] | |
| (and (wcar* | |
| (car/set id (value->entry value)) | |
| (car/expire id (expiration policy))) | |
| value))) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Cache maintenance | |
| (defn cleanup | |
| ([] (cleanup nil)) | |
| ([k] | |
| (let [ks (wcar* (car/keys (str (key->id k) "*")))] | |
| (when-not (empty? ks) | |
| (wcar* (apply car/del ks)))))) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;;; Public API | |
| (defmacro with-cache | |
| [key policy & body] | |
| `(or (cache-get ~key ~policy) | |
| (cache-set ~key ~policy (do ~@body)))) | |
| (comment | |
| (with-cache :spikes (for-seconds 5) | |
| (println "Side effects") | |
| 42) | |
| (with-cache [:spikes 1] (for-seconds 5) | |
| (println "Side effects") | |
| 42)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment