Created
October 16, 2013 21:45
-
-
Save samn/7015449 to your computer and use it in GitHub Desktop.
This shows a technique for waiting for an asynchronous operation (here persistence) to occur without using locks. This is useful if we normally want this operation to occur asynchronously (in a future thread pool) but would like to wait for its completion at exceptional times. For example, it may be fine to periodically persist data asynchronous…
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
(defn wait-for-persistence | |
"Dereferences and waits on the value of persistence-lock-atom, | |
if the value is dereferenceble & returns the dereferenced value. | |
Otherwise returns nil." | |
[persistence-lock-atom] | |
(when (instance? clojure.lang.IDeref @persistence-lock-atom) | |
;; This could deref with a timeout by using `deref` instead of `@` | |
@@persistence-lock-atom)) | |
(defn persist! | |
"Persist some resource. | |
Noops if persistence is already happening." | |
[persistence-lock-atom] | |
(let [completion-promise (promise)] | |
(future | |
;; compare-and-set! returns true if the set happened, i.e. if the | |
;; old-val was false which means persistence isn't already happening. | |
;; Set persistence-lock-atom to a promise to communicate the completion of | |
;; this async persistence. | |
(when (compare-and-set! persistence-lock-atom false completion-promise) | |
(do-something-that-persists) | |
(deliver completion-promise :complete) | |
;; reset the lock atom so the next persistence can happen. if someone was waiting | |
;; on the completion promise to see if this persistence occurred they'll see the | |
;; deliver above. | |
(reset! persistence-lock-atom false))))) | |
(let [persistence-lock (atom false)] | |
(persist! persistence-lock) | |
(wait-for-persistence persistence-lock)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment